Aurora Framework  ${AURORAFW_VERSION}
A Powerful General Purpose Framework
ImGui.cpp
Go to the documentation of this file.
1 // dear imgui, v1.60 WIP
2 // (main code and documentation)
3 
4 // Call and read ImGui::ShowDemoWindow() in imgui_demo.cpp for demo code.
5 // Newcomers, read 'Programmer guide' below for notes on how to setup Dear ImGui in your codebase.
6 // Get latest version at https://github.com/ocornut/imgui
7 // Releases change-log at https://github.com/ocornut/imgui/releases
8 // Gallery (please post your screenshots/video there!): https://github.com/ocornut/imgui/issues/1269
9 // Developed by Omar Cornut and every direct or indirect contributors to the GitHub.
10 // This library is free but I need your support to sustain development and maintenance.
11 // If you work for a company, please consider financial support, see Readme. For individuals: https://www.patreon.com/imgui
12 
13 /*
14 
15  Index
16  - MISSION STATEMENT
17  - END-USER GUIDE
18  - PROGRAMMER GUIDE (read me!)
19  - Read first
20  - How to update to a newer version of Dear ImGui
21  - Getting started with integrating Dear ImGui in your code/engine
22  - Using gamepad/keyboard navigation [BETA]
23  - API BREAKING CHANGES (read me when you update!)
24  - ISSUES & TODO LIST
25  - FREQUENTLY ASKED QUESTIONS (FAQ), TIPS
26  - How can I help?
27  - How can I display an image? What is ImTextureID, how does it works?
28  - How can I have multiple widgets with the same label? Can I have widget without a label? (Yes). A primer on labels and the ID stack.
29  - How can I tell when Dear ImGui wants my mouse/keyboard inputs VS when I can pass them to my application?
30  - How can I load a different font than the default?
31  - How can I easily use icons in my application?
32  - How can I load multiple fonts?
33  - How can I display and input non-latin characters such as Chinese, Japanese, Korean, Cyrillic?
34  - How can I preserve my Dear ImGui context across reloading a DLL? (loss of the global/static variables)
35  - How can I use the drawing facilities without an ImGui window? (using ImDrawList API)
36  - I integrated Dear ImGui in my engine and the text or lines are blurry..
37  - I integrated Dear ImGui in my engine and some elements are clipping or disappearing when I move windows around..
38  - ISSUES & TODO-LIST
39  - CODE
40 
41 
42  MISSION STATEMENT
43  =================
44 
45  - Easy to use to create code-driven and data-driven tools
46  - Easy to use to create ad hoc short-lived tools and long-lived, more elaborate tools
47  - Easy to hack and improve
48  - Minimize screen real-estate usage
49  - Minimize setup and maintenance
50  - Minimize state storage on user side
51  - Portable, minimize dependencies, run on target (consoles, phones, etc.)
52  - Efficient runtime and memory consumption (NB- we do allocate when "growing" content e.g. creating a window, opening a tree node
53  for the first time, etc. but a typical frame won't allocate anything)
54 
55  Designed for developers and content-creators, not the typical end-user! Some of the weaknesses includes:
56  - Doesn't look fancy, doesn't animate
57  - Limited layout features, intricate layouts are typically crafted in code
58 
59 
60  END-USER GUIDE
61  ==============
62 
63  - Double-click on title bar to collapse window.
64  - Click upper right corner to close a window, available when 'bool* p_open' is passed to ImGui::Begin().
65  - Click and drag on lower right corner to resize window (double-click to auto fit window to its contents).
66  - Click and drag on any empty space to move window.
67  - TAB/SHIFT+TAB to cycle through keyboard editable fields.
68  - CTRL+Click on a slider or drag box to input value as text.
69  - Use mouse wheel to scroll.
70  - Text editor:
71  - Hold SHIFT or use mouse to select text.
72  - CTRL+Left/Right to word jump.
73  - CTRL+Shift+Left/Right to select words.
74  - CTRL+A our Double-Click to select all.
75  - CTRL+X,CTRL+C,CTRL+V to use OS clipboard/
76  - CTRL+Z,CTRL+Y to undo/redo.
77  - ESCAPE to revert text to its original value.
78  - You can apply arithmetic operators +,*,/ on numerical values. Use +- to subtract (because - would set a negative value!)
79  - Controls are automatically adjusted for OSX to match standard OSX text editing operations.
80  - Gamepad navigation: see suggested mappings in imgui.h ImGuiNavInput_ + download PNG/PSD at goo.gl/9LgVZW.
81 
82 
83  PROGRAMMER GUIDE
84  ================
85 
86  READ FIRST
87 
88  - Read the FAQ below this section!
89  - Your code creates the UI, if your code doesn't run the UI is gone! == very dynamic UI, no construction/destructions steps, less data retention
90  on your side, no state duplication, less sync, less bugs.
91  - Call and read ImGui::ShowDemoWindow() for demo code demonstrating most features.
92  - You can learn about immediate-mode gui principles at http://www.johno.se/book/imgui.html or watch http://mollyrocket.com/861
93 
94  HOW TO UPDATE TO A NEWER VERSION OF DEAR IMGUI
95 
96  - Overwrite all the sources files except for imconfig.h (if you have made modification to your copy of imconfig.h)
97  - Read the "API BREAKING CHANGES" section (below). This is where we list occasional API breaking changes.
98  If a function/type has been renamed / or marked obsolete, try to fix the name in your code before it is permanently removed from the public API.
99  If you have a problem with a missing function/symbols, search for its name in the code, there will likely be a comment about it.
100  Please report any issue to the GitHub page!
101  - Try to keep your copy of dear imgui reasonably up to date.
102 
103  GETTING STARTED WITH INTEGRATING DEAR IMGUI IN YOUR CODE/ENGINE
104 
105  - Add the Dear ImGui source files to your projects, using your preferred build system.
106  It is recommended you build the .cpp files as part of your project and not as a library.
107  - You can later customize the imconfig.h file to tweak some compilation time behavior, such as integrating imgui types with your own maths types.
108  - See examples/ folder for standalone sample applications.
109  - You may be able to grab and copy a ready made imgui_impl_*** file from the examples/.
110  - When using Dear ImGui, your programming IDE is your friend: follow the declaration of variables, functions and types to find comments about them.
111 
112  - Init: retrieve the ImGuiIO structure with ImGui::GetIO() and fill the fields marked 'Settings': at minimum you need to set io.DisplaySize
113  (application resolution). Later on you will fill your keyboard mapping, clipboard handlers, and other advanced features but for a basic
114  integration you don't need to worry about it all.
115  - Init: call io.Fonts->GetTexDataAsRGBA32(...), it will build the font atlas texture, then load the texture pixels into graphics memory.
116  - Every frame:
117  - In your main loop as early a possible, fill the IO fields marked 'Input' (e.g. mouse position, buttons, keyboard info, etc.)
118  - Call ImGui::NewFrame() to begin the frame
119  - You can use any ImGui function you want between NewFrame() and Render()
120  - Call ImGui::Render() as late as you can to end the frame and finalize render data. it will call your io.RenderDrawListFn handler.
121  (Even if you don't render, call Render() and ignore the callback, or call EndFrame() instead. Otherwhise some features will break)
122  - All rendering information are stored into command-lists until ImGui::Render() is called.
123  - Dear ImGui never touches or knows about your GPU state. the only function that knows about GPU is the RenderDrawListFn handler that you provide.
124  - Effectively it means you can create widgets at any time in your code, regardless of considerations of being in "update" vs "render" phases
125  of your own application.
126  - Refer to the examples applications in the examples/ folder for instruction on how to setup your code.
127  - A minimal application skeleton may be:
128 
129  // Application init
130  ImGui::CreateContext();
131  ImGuiIO& io = ImGui::GetIO();
132  io.DisplaySize.x = 1920.0f;
133  io.DisplaySize.y = 1280.0f;
134  // TODO: Fill others settings of the io structure later.
135 
136  // Load texture atlas (there is a default font so you don't need to care about choosing a font yet)
137  unsigned char* pixels;
138  int width, height;
139  io.Fonts->GetTexDataAsRGBA32(pixels, &width, &height);
140  // TODO: At this points you've got the texture data and you need to upload that your your graphic system:
141  MyTexture* texture = MyEngine::CreateTextureFromMemoryPixels(pixels, width, height, TEXTURE_TYPE_RGBA)
142  // TODO: Store your texture pointer/identifier (whatever your engine uses) in 'io.Fonts->TexID'. This will be passed back to your via the renderer.
143  io.Fonts->TexID = (void*)texture;
144 
145  // Application main loop
146  while (true)
147  {
148  // Setup low-level inputs (e.g. on Win32, GetKeyboardState(), or write to those fields from your Windows message loop handlers, etc.)
149  ImGuiIO& io = ImGui::GetIO();
150  io.DeltaTime = 1.0f/60.0f;
151  io.MousePos = mouse_pos;
152  io.MouseDown[0] = mouse_button_0;
153  io.MouseDown[1] = mouse_button_1;
154 
155  // Call NewFrame(), after this point you can use ImGui::* functions anytime
156  ImGui::NewFrame();
157 
158  // Most of your application code here
159  MyGameUpdate(); // may use any ImGui functions, e.g. ImGui::Begin("My window"); ImGui::Text("Hello, world!"); ImGui::End();
160  MyGameRender(); // may use any ImGui functions as well!
161 
162  // Render & swap video buffers
163  ImGui::Render();
164  MyImGuiRenderFunction(ImGui::GetDrawData());
165  SwapBuffers();
166  }
167 
168  // Shutdown
169  ImGui::DestroyContext();
170 
171 
172  - A minimal render function skeleton may be:
173 
174  void void MyRenderFunction(ImDrawData* draw_data)
175  {
176  // TODO: Setup render state: alpha-blending enabled, no face culling, no depth testing, scissor enabled
177  // TODO: Setup viewport, orthographic projection matrix
178  // TODO: Setup shader: vertex { float2 pos, float2 uv, u32 color }, fragment shader sample color from 1 texture, multiply by vertex color.
179  for (int n = 0; n < draw_data->CmdListsCount; n++)
180  {
181  const ImDrawVert* vtx_buffer = cmd_list->VtxBuffer.Data; // vertex buffer generated by ImGui
182  const ImDrawIdx* idx_buffer = cmd_list->IdxBuffer.Data; // index buffer generated by ImGui
183  for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++)
184  {
185  const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i];
186  if (pcmd->UserCallback)
187  {
188  pcmd->UserCallback(cmd_list, pcmd);
189  }
190  else
191  {
192  // The texture for the draw call is specified by pcmd->TextureId.
193  // The vast majority of draw calls with use the imgui texture atlas, which value you have set yourself during initialization.
194  MyEngineBindTexture(pcmd->TextureId);
195 
196  // We are using scissoring to clip some objects. All low-level graphics API supports it.
197  // If your engine doesn't support scissoring yet, you will get some small glitches (some elements outside their bounds) which you can fix later.
198  MyEngineScissor((int)pcmd->ClipRect.x, (int)pcmd->ClipRect.y, (int)(pcmd->ClipRect.z - pcmd->ClipRect.x), (int)(pcmd->ClipRect.w - pcmd->ClipRect.y));
199 
200  // Render 'pcmd->ElemCount/3' indexed triangles.
201  // By default the indices ImDrawIdx are 16-bits, you can change them to 32-bits if your engine doesn't support 16-bits indices.
202  MyEngineDrawIndexedTriangles(pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, idx_buffer, vtx_buffer);
203  }
204  idx_buffer += pcmd->ElemCount;
205  }
206  }
207  }
208 
209  - The examples/ folders contains many functional implementation of the pseudo-code above.
210  - When calling NewFrame(), the 'io.WantCaptureMouse'/'io.WantCaptureKeyboard'/'io.WantTextInput' flags are updated.
211  They tell you if ImGui intends to use your inputs. So for example, if 'io.WantCaptureMouse' is set you would typically want to hide
212  mouse inputs from the rest of your application. Read the FAQ below for more information about those flags.
213 
214  USING GAMEPAD/KEYBOARD NAVIGATION [BETA]
215 
216  - Ask questions and report issues at https://github.com/ocornut/imgui/issues/787
217  - The initial focus was to support game controllers, but keyboard is becoming increasingly and decently usable.
218  - Keyboard:
219  - Set io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard to enable. NewFrame() will automatically fill io.NavInputs[] based on your io.KeyDown[] + io.KeyMap[] arrays.
220  - When keyboard navigation is active (io.NavActive + ImGuiConfigFlags_NavEnableKeyboard), the io.WantCaptureKeyboard flag will be set.
221  For more advanced uses, you may want to read from:
222  - io.NavActive: true when a window is focused and it doesn't have the ImGuiWindowFlags_NoNavInputs flag set.
223  - io.NavVisible: true when the navigation cursor is visible (and usually goes false when mouse is used).
224  - or query focus information with e.g. IsWindowFocused(), IsItemFocused() etc. functions.
225  Please reach out if you think the game vs navigation input sharing could be improved.
226  - Gamepad:
227  - Set io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad to enable. Fill the io.NavInputs[] fields before calling NewFrame(). Note that io.NavInputs[] is cleared by EndFrame().
228  - See 'enum ImGuiNavInput_' in imgui.h for a description of inputs. For each entry of io.NavInputs[], set the following values:
229  0.0f= not held. 1.0f= fully held. Pass intermediate 0.0f..1.0f values for analog triggers/sticks.
230  - We uses a simple >0.0f test for activation testing, and won't attempt to test for a dead-zone.
231  Your code will probably need to transform your raw inputs (such as e.g. remapping your 0.2..0.9 raw input range to 0.0..1.0 imgui range, maybe a power curve, etc.).
232  - You can download PNG/PSD files depicting the gamepad controls for common controllers at: goo.gl/9LgVZW.
233  - If you need to share inputs between your game and the imgui parts, the easiest approach is to go all-or-nothing, with a buttons combo to toggle the target.
234  Please reach out if you think the game vs navigation input sharing could be improved.
235  - Mouse:
236  - PS4 users: Consider emulating a mouse cursor with DualShock4 touch pad or a spare analog stick as a mouse-emulation fallback.
237  - Consoles/Tablet/Phone users: Consider using Synergy host (on your computer) + uSynergy.c (in your console/tablet/phone app) to use your PC mouse/keyboard.
238  - On a TV/console system where readability may be lower or mouse inputs may be awkward, you may want to set the ImGuiConfigFlags_NavMoveMouse flag.
239  Enabling ImGuiConfigFlags_NavMoveMouse instructs dear imgui to move your mouse cursor along with navigation movements.
240  When enabled, the NewFrame() function may alter 'io.MousePos' and set 'io.WantMoveMouse' to notify you that it wants the mouse cursor to be moved.
241  When that happens your back-end NEEDS to move the OS or underlying mouse cursor on the next frame. Some of the binding in examples/ do that.
242  (If you set the NavMoveMouse flag but don't honor 'io.WantMoveMouse' properly, imgui will misbehave as it will see your mouse as moving back and forth!)
243  (In a setup when you may not have easy control over the mouse cursor, e.g. uSynergy.c doesn't expose moving remote mouse cursor, you may want
244  to set a boolean to ignore your other external mouse positions until the external source is moved again.)
245 
246 
247  API BREAKING CHANGES
248  ====================
249 
250  Occasionally introducing changes that are breaking the API. The breakage are generally minor and easy to fix.
251  Here is a change-log of API breaking changes, if you are using one of the functions listed, expect to have to fix some code.
252  Also read releases logs https://github.com/ocornut/imgui/releases for more details.
253 
254  - 2018/02/18 (1.60) - BeginDragDropSource(): temporarily removed the optional mouse_button=0 parameter because it is not really usable in many situations at the moment.
255  - 2018/02/16 (1.60) - obsoleted the io.RenderDrawListsFn callback, you can call your graphics engine render function after ImGui::Render(). Use ImGui::GetDrawData() to retrieve the ImDrawData* to display.
256  - 2018/02/07 (1.60) - reorganized context handling to be more explicit,
257  - YOU NOW NEED TO CALL ImGui::CreateContext() AT THE BEGINNING OF YOUR APP, AND CALL ImGui::DestroyContext() AT THE END.
258  - removed Shutdown() function, as DestroyContext() serve this purpose.
259  - you may pass a ImFontAtlas* pointer to CreateContext() to share a font atlas between contexts. Otherwhise CreateContext() will create its own font atlas instance.
260  - removed allocator parameters from CreateContext(), they are now setup with SetAllocatorFunctions(), and shared by all contexts.
261  - removed the default global context and font atlas instance, which were confusing for users of DLL reloading and users of multiple contexts.
262  - 2018/01/31 (1.60) - moved sample TTF files from extra_fonts/ to misc/fonts/. If you loaded files directly from the imgui repo you may need to update your paths.
263  - 2018/01/11 (1.60) - obsoleted IsAnyWindowHovered() in favor of IsWindowHovered(ImGuiHoveredFlags_AnyWindow). Kept redirection function (will obsolete).
264  - 2018/01/11 (1.60) - obsoleted IsAnyWindowFocused() in favor of IsWindowFocused(ImGuiFocusedFlags_AnyWindow). Kept redirection function (will obsolete).
265  - 2018/01/03 (1.60) - renamed ImGuiSizeConstraintCallback to ImGuiSizeCallback, ImGuiSizeConstraintCallbackData to ImGuiSizeCallbackData.
266  - 2017/12/29 (1.60) - removed CalcItemRectClosestPoint() which was weird and not really used by anyone except demo code. If you need it it's easy to replicate on your side.
267  - 2017/12/24 (1.53) - renamed the emblematic ShowTestWindow() function to ShowDemoWindow(). Kept redirection function (will obsolete).
268  - 2017/12/21 (1.53) - ImDrawList: renamed style.AntiAliasedShapes to style.AntiAliasedFill for consistency and as a way to explicitly break code that manipulate those flag at runtime. You can now manipulate ImDrawList::Flags
269  - 2017/12/21 (1.53) - ImDrawList: removed 'bool anti_aliased = true' final parameter of ImDrawList::AddPolyline() and ImDrawList::AddConvexPolyFilled(). Prefer manipulating ImDrawList::Flags if you need to toggle them during the frame.
270  - 2017/12/14 (1.53) - using the ImGuiWindowFlags_NoScrollWithMouse flag on a child window forwards the mouse wheel event to the parent window, unless either ImGuiWindowFlags_NoInputs or ImGuiWindowFlags_NoScrollbar are also set.
271  - 2017/12/13 (1.53) - renamed GetItemsLineHeightWithSpacing() to GetFrameHeightWithSpacing(). Kept redirection function (will obsolete).
272  - 2017/12/13 (1.53) - obsoleted IsRootWindowFocused() in favor of using IsWindowFocused(ImGuiFocusedFlags_RootWindow). Kept redirection function (will obsolete).
273  - obsoleted IsRootWindowOrAnyChildFocused() in favor of using IsWindowFocused(ImGuiFocusedFlags_RootAndChildWindows). Kept redirection function (will obsolete).
274  - 2017/12/12 (1.53) - renamed ImGuiTreeNodeFlags_AllowOverlapMode to ImGuiTreeNodeFlags_AllowItemOverlap. Kept redirection enum (will obsolete).
275  - 2017/12/10 (1.53) - removed SetNextWindowContentWidth(), prefer using SetNextWindowContentSize(). Kept redirection function (will obsolete).
276  - 2017/11/27 (1.53) - renamed ImGuiTextBuffer::append() helper to appendf(), appendv() to appendfv(). If you copied the 'Log' demo in your code, it uses appendv() so that needs to be renamed.
277  - 2017/11/18 (1.53) - Style, Begin: removed ImGuiWindowFlags_ShowBorders window flag. Borders are now fully set up in the ImGuiStyle structure (see e.g. style.FrameBorderSize, style.WindowBorderSize). Use ImGui::ShowStyleEditor() to look them up.
278  Please note that the style system will keep evolving (hopefully stabilizing in Q1 2018), and so custom styles will probably subtly break over time. It is recommended you use the StyleColorsClassic(), StyleColorsDark(), StyleColorsLight() functions.
279  - 2017/11/18 (1.53) - Style: removed ImGuiCol_ComboBg in favor of combo boxes using ImGuiCol_PopupBg for consistency.
280  - 2017/11/18 (1.53) - Style: renamed ImGuiCol_ChildWindowBg to ImGuiCol_ChildBg.
281  - 2017/11/18 (1.53) - Style: renamed style.ChildWindowRounding to style.ChildRounding, ImGuiStyleVar_ChildWindowRounding to ImGuiStyleVar_ChildRounding.
282  - 2017/11/02 (1.53) - obsoleted IsRootWindowOrAnyChildHovered() in favor of using IsWindowHovered(ImGuiHoveredFlags_RootAndChildWindows);
283  - 2017/10/24 (1.52) - renamed IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCS/IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCS to IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS/IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS for consistency.
284  - 2017/10/20 (1.52) - changed IsWindowHovered() default parameters behavior to return false if an item is active in another window (e.g. click-dragging item from another window to this window). You can use the newly introduced IsWindowHovered() flags to requests this specific behavior if you need it.
285  - 2017/10/20 (1.52) - marked IsItemHoveredRect()/IsMouseHoveringWindow() as obsolete, in favor of using the newly introduced flags for IsItemHovered() and IsWindowHovered(). See https://github.com/ocornut/imgui/issues/1382 for details.
286  removed the IsItemRectHovered()/IsWindowRectHovered() names introduced in 1.51 since they were merely more consistent names for the two functions we are now obsoleting.
287  - 2017/10/17 (1.52) - marked the old 5-parameters version of Begin() as obsolete (still available). Use SetNextWindowSize()+Begin() instead!
288  - 2017/10/11 (1.52) - renamed AlignFirstTextHeightToWidgets() to AlignTextToFramePadding(). Kept inline redirection function (will obsolete).
289  - 2017/09/25 (1.52) - removed SetNextWindowPosCenter() because SetNextWindowPos() now has the optional pivot information to do the same and more. Kept redirection function (will obsolete).
290  - 2017/08/25 (1.52) - io.MousePos needs to be set to ImVec2(-FLT_MAX,-FLT_MAX) when mouse is unavailable/missing. Previously ImVec2(-1,-1) was enough but we now accept negative mouse coordinates. In your binding if you need to support unavailable mouse, make sure to replace "io.MousePos = ImVec2(-1,-1)" with "io.MousePos = ImVec2(-FLT_MAX,-FLT_MAX)".
291  - 2017/08/22 (1.51) - renamed IsItemHoveredRect() to IsItemRectHovered(). Kept inline redirection function (will obsolete). -> (1.52) use IsItemHovered(ImGuiHoveredFlags_RectOnly)!
292  - renamed IsMouseHoveringAnyWindow() to IsAnyWindowHovered() for consistency. Kept inline redirection function (will obsolete).
293  - renamed IsMouseHoveringWindow() to IsWindowRectHovered() for consistency. Kept inline redirection function (will obsolete).
294  - 2017/08/20 (1.51) - renamed GetStyleColName() to GetStyleColorName() for consistency.
295  - 2017/08/20 (1.51) - added PushStyleColor(ImGuiCol idx, ImU32 col) overload, which _might_ cause an "ambiguous call" compilation error if you are using ImColor() with implicit cast. Cast to ImU32 or ImVec4 explicily to fix.
296  - 2017/08/15 (1.51) - marked the weird IMGUI_ONCE_UPON_A_FRAME helper macro as obsolete. prefer using the more explicit ImGuiOnceUponAFrame.
297  - 2017/08/15 (1.51) - changed parameter order for BeginPopupContextWindow() from (const char*,int buttons,bool also_over_items) to (const char*,int buttons,bool also_over_items). Note that most calls relied on default parameters completely.
298  - 2017/08/13 (1.51) - renamed ImGuiCol_Columns*** to ImGuiCol_Separator***. Kept redirection enums (will obsolete).
299  - 2017/08/11 (1.51) - renamed ImGuiSetCond_*** types and flags to ImGuiCond_***. Kept redirection enums (will obsolete).
300  - 2017/08/09 (1.51) - removed ValueColor() helpers, they are equivalent to calling Text(label) + SameLine() + ColorButton().
301  - 2017/08/08 (1.51) - removed ColorEditMode() and ImGuiColorEditMode in favor of ImGuiColorEditFlags and parameters to the various Color*() functions. The SetColorEditOptions() allows to initialize default but the user can still change them with right-click context menu.
302  - changed prototype of 'ColorEdit4(const char* label, float col[4], bool show_alpha = true)' to 'ColorEdit4(const char* label, float col[4], ImGuiColorEditFlags flags = 0)', where passing flags = 0x01 is a safe no-op (hello dodgy backward compatibility!). - check and run the demo window, under "Color/Picker Widgets", to understand the various new options.
303  - changed prototype of rarely used 'ColorButton(ImVec4 col, bool small_height = false, bool outline_border = true)' to 'ColorButton(const char* desc_id, ImVec4 col, ImGuiColorEditFlags flags = 0, ImVec2 size = ImVec2(0,0))'
304  - 2017/07/20 (1.51) - removed IsPosHoveringAnyWindow(ImVec2), which was partly broken and misleading. ASSERT + redirect user to io.WantCaptureMouse
305  - 2017/05/26 (1.50) - removed ImFontConfig::MergeGlyphCenterV in favor of a more multipurpose ImFontConfig::GlyphOffset.
306  - 2017/05/01 (1.50) - renamed ImDrawList::PathFill() (rarely used directly) to ImDrawList::PathFillConvex() for clarity.
307  - 2016/11/06 (1.50) - BeginChild(const char*) now applies the stack id to the provided label, consistently with other functions as it should always have been. It shouldn't affect you unless (extremely unlikely) you were appending multiple times to a same child from different locations of the stack id. If that's the case, generate an id with GetId() and use it instead of passing string to BeginChild().
308  - 2016/10/15 (1.50) - avoid 'void* user_data' parameter to io.SetClipboardTextFn/io.GetClipboardTextFn pointers. We pass io.ClipboardUserData to it.
309  - 2016/09/25 (1.50) - style.WindowTitleAlign is now a ImVec2 (ImGuiAlign enum was removed). set to (0.5f,0.5f) for horizontal+vertical centering, (0.0f,0.0f) for upper-left, etc.
310  - 2016/07/30 (1.50) - SameLine(x) with x>0.0f is now relative to left of column/group if any, and not always to left of window. This was sort of always the intent and hopefully breakage should be minimal.
311  - 2016/05/12 (1.49) - title bar (using ImGuiCol_TitleBg/ImGuiCol_TitleBgActive colors) isn't rendered over a window background (ImGuiCol_WindowBg color) anymore.
312  If your TitleBg/TitleBgActive alpha was 1.0f or you are using the default theme it will not affect you.
313  However if your TitleBg/TitleBgActive alpha was <1.0f you need to tweak your custom theme to readjust for the fact that we don't draw a WindowBg background behind the title bar.
314  This helper function will convert an old TitleBg/TitleBgActive color into a new one with the same visual output, given the OLD color and the OLD WindowBg color.
315  ImVec4 ConvertTitleBgCol(const ImVec4& win_bg_col, const ImVec4& title_bg_col)
316  {
317  float new_a = 1.0f - ((1.0f - win_bg_col.w) * (1.0f - title_bg_col.w)), k = title_bg_col.w / new_a;
318  return ImVec4((win_bg_col.x * win_bg_col.w + title_bg_col.x) * k, (win_bg_col.y * win_bg_col.w + title_bg_col.y) * k, (win_bg_col.z * win_bg_col.w + title_bg_col.z) * k, new_a);
319  }
320  If this is confusing, pick the RGB value from title bar from an old screenshot and apply this as TitleBg/TitleBgActive. Or you may just create TitleBgActive from a tweaked TitleBg color.
321  - 2016/05/07 (1.49) - removed confusing set of GetInternalState(), GetInternalStateSize(), SetInternalState() functions. Now using CreateContext(), DestroyContext(), GetCurrentContext(), SetCurrentContext().
322  - 2016/05/02 (1.49) - renamed SetNextTreeNodeOpened() to SetNextTreeNodeOpen(), no redirection.
323  - 2016/05/01 (1.49) - obsoleted old signature of CollapsingHeader(const char* label, const char* str_id = NULL, bool display_frame = true, bool default_open = false) as extra parameters were badly designed and rarely used. You can replace the "default_open = true" flag in new API with CollapsingHeader(label, ImGuiTreeNodeFlags_DefaultOpen).
324  - 2016/04/26 (1.49) - changed ImDrawList::PushClipRect(ImVec4 rect) to ImDraw::PushClipRect(Imvec2 min,ImVec2 max,bool intersect_with_current_clip_rect=false). Note that higher-level ImGui::PushClipRect() is preferable because it will clip at logic/widget level, whereas ImDrawList::PushClipRect() only affect your renderer.
325  - 2016/04/03 (1.48) - removed style.WindowFillAlphaDefault setting which was redundant. Bake default BG alpha inside style.Colors[ImGuiCol_WindowBg] and all other Bg color values. (ref github issue #337).
326  - 2016/04/03 (1.48) - renamed ImGuiCol_TooltipBg to ImGuiCol_PopupBg, used by popups/menus and tooltips. popups/menus were previously using ImGuiCol_WindowBg. (ref github issue #337)
327  - 2016/03/21 (1.48) - renamed GetWindowFont() to GetFont(), GetWindowFontSize() to GetFontSize(). Kept inline redirection function (will obsolete).
328  - 2016/03/02 (1.48) - InputText() completion/history/always callbacks: if you modify the text buffer manually (without using DeleteChars()/InsertChars() helper) you need to maintain the BufTextLen field. added an assert.
329  - 2016/01/23 (1.48) - fixed not honoring exact width passed to PushItemWidth(), previously it would add extra FramePadding.x*2 over that width. if you had manual pixel-perfect alignment in place it might affect you.
330  - 2015/12/27 (1.48) - fixed ImDrawList::AddRect() which used to render a rectangle 1 px too large on each axis.
331  - 2015/12/04 (1.47) - renamed Color() helpers to ValueColor() - dangerously named, rarely used and probably to be made obsolete.
332  - 2015/08/29 (1.45) - with the addition of horizontal scrollbar we made various fixes to inconsistencies with dealing with cursor position.
333  GetCursorPos()/SetCursorPos() functions now include the scrolled amount. It shouldn't affect the majority of users, but take note that SetCursorPosX(100.0f) puts you at +100 from the starting x position which may include scrolling, not at +100 from the window left side.
334  GetContentRegionMax()/GetWindowContentRegionMin()/GetWindowContentRegionMax() functions allow include the scrolled amount. Typically those were used in cases where no scrolling would happen so it may not be a problem, but watch out!
335  - 2015/08/29 (1.45) - renamed style.ScrollbarWidth to style.ScrollbarSize
336  - 2015/08/05 (1.44) - split imgui.cpp into extra files: imgui_demo.cpp imgui_draw.cpp imgui_internal.h that you need to add to your project.
337  - 2015/07/18 (1.44) - fixed angles in ImDrawList::PathArcTo(), PathArcToFast() (introduced in 1.43) being off by an extra PI for no justifiable reason
338  - 2015/07/14 (1.43) - add new ImFontAtlas::AddFont() API. For the old AddFont***, moved the 'font_no' parameter of ImFontAtlas::AddFont** functions to the ImFontConfig structure.
339  you need to render your textured triangles with bilinear filtering to benefit from sub-pixel positioning of text.
340  - 2015/07/08 (1.43) - switched rendering data to use indexed rendering. this is saving a fair amount of CPU/GPU and enables us to get anti-aliasing for a marginal cost.
341  this necessary change will break your rendering function! the fix should be very easy. sorry for that :(
342  - if you are using a vanilla copy of one of the imgui_impl_XXXX.cpp provided in the example, you just need to update your copy and you can ignore the rest.
343  - the signature of the io.RenderDrawListsFn handler has changed!
344  old: ImGui_XXXX_RenderDrawLists(ImDrawList** const cmd_lists, int cmd_lists_count)
345  new: ImGui_XXXX_RenderDrawLists(ImDrawData* draw_data).
346  argument: 'cmd_lists' becomes 'draw_data->CmdLists', 'cmd_lists_count' becomes 'draw_data->CmdListsCount'
347  ImDrawList: 'commands' becomes 'CmdBuffer', 'vtx_buffer' becomes 'VtxBuffer', 'IdxBuffer' is new.
348  ImDrawCmd: 'vtx_count' becomes 'ElemCount', 'clip_rect' becomes 'ClipRect', 'user_callback' becomes 'UserCallback', 'texture_id' becomes 'TextureId'.
349  - each ImDrawList now contains both a vertex buffer and an index buffer. For each command, render ElemCount/3 triangles using indices from the index buffer.
350  - if you REALLY cannot render indexed primitives, you can call the draw_data->DeIndexAllBuffers() method to de-index the buffers. This is slow and a waste of CPU/GPU. Prefer using indexed rendering!
351  - refer to code in the examples/ folder or ask on the GitHub if you are unsure of how to upgrade. please upgrade!
352  - 2015/07/10 (1.43) - changed SameLine() parameters from int to float.
353  - 2015/07/02 (1.42) - renamed SetScrollPosHere() to SetScrollFromCursorPos(). Kept inline redirection function (will obsolete).
354  - 2015/07/02 (1.42) - renamed GetScrollPosY() to GetScrollY(). Necessary to reduce confusion along with other scrolling functions, because positions (e.g. cursor position) are not equivalent to scrolling amount.
355  - 2015/06/14 (1.41) - changed ImageButton() default bg_col parameter from (0,0,0,1) (black) to (0,0,0,0) (transparent) - makes a difference when texture have transparence
356  - 2015/06/14 (1.41) - changed Selectable() API from (label, selected, size) to (label, selected, flags, size). Size override should have been rarely be used. Sorry!
357  - 2015/05/31 (1.40) - renamed GetWindowCollapsed() to IsWindowCollapsed() for consistency. Kept inline redirection function (will obsolete).
358  - 2015/05/31 (1.40) - renamed IsRectClipped() to IsRectVisible() for consistency. Note that return value is opposite! Kept inline redirection function (will obsolete).
359  - 2015/05/27 (1.40) - removed the third 'repeat_if_held' parameter from Button() - sorry! it was rarely used and inconsistent. Use PushButtonRepeat(true) / PopButtonRepeat() to enable repeat on desired buttons.
360  - 2015/05/11 (1.40) - changed BeginPopup() API, takes a string identifier instead of a bool. ImGui needs to manage the open/closed state of popups. Call OpenPopup() to actually set the "open" state of a popup. BeginPopup() returns true if the popup is opened.
361  - 2015/05/03 (1.40) - removed style.AutoFitPadding, using style.WindowPadding makes more sense (the default values were already the same).
362  - 2015/04/13 (1.38) - renamed IsClipped() to IsRectClipped(). Kept inline redirection function until 1.50.
363  - 2015/04/09 (1.38) - renamed ImDrawList::AddArc() to ImDrawList::AddArcFast() for compatibility with future API
364  - 2015/04/03 (1.38) - removed ImGuiCol_CheckHovered, ImGuiCol_CheckActive, replaced with the more general ImGuiCol_FrameBgHovered, ImGuiCol_FrameBgActive.
365  - 2014/04/03 (1.38) - removed support for passing -FLT_MAX..+FLT_MAX as the range for a SliderFloat(). Use DragFloat() or Inputfloat() instead.
366  - 2015/03/17 (1.36) - renamed GetItemBoxMin()/GetItemBoxMax()/IsMouseHoveringBox() to GetItemRectMin()/GetItemRectMax()/IsMouseHoveringRect(). Kept inline redirection function until 1.50.
367  - 2015/03/15 (1.36) - renamed style.TreeNodeSpacing to style.IndentSpacing, ImGuiStyleVar_TreeNodeSpacing to ImGuiStyleVar_IndentSpacing
368  - 2015/03/13 (1.36) - renamed GetWindowIsFocused() to IsWindowFocused(). Kept inline redirection function until 1.50.
369  - 2015/03/08 (1.35) - renamed style.ScrollBarWidth to style.ScrollbarWidth (casing)
370  - 2015/02/27 (1.34) - renamed OpenNextNode(bool) to SetNextTreeNodeOpened(bool, ImGuiSetCond). Kept inline redirection function until 1.50.
371  - 2015/02/27 (1.34) - renamed ImGuiSetCondition_*** to ImGuiSetCond_***, and _FirstUseThisSession becomes _Once.
372  - 2015/02/11 (1.32) - changed text input callback ImGuiTextEditCallback return type from void-->int. reserved for future use, return 0 for now.
373  - 2015/02/10 (1.32) - renamed GetItemWidth() to CalcItemWidth() to clarify its evolving behavior
374  - 2015/02/08 (1.31) - renamed GetTextLineSpacing() to GetTextLineHeightWithSpacing()
375  - 2015/02/01 (1.31) - removed IO.MemReallocFn (unused)
376  - 2015/01/19 (1.30) - renamed ImGuiStorage::GetIntPtr()/GetFloatPtr() to GetIntRef()/GetIntRef() because Ptr was conflicting with actual pointer storage functions.
377  - 2015/01/11 (1.30) - big font/image API change! now loads TTF file. allow for multiple fonts. no need for a PNG loader.
378  (1.30) - removed GetDefaultFontData(). uses io.Fonts->GetTextureData*() API to retrieve uncompressed pixels.
379  font init: const void* png_data; unsigned int png_size; ImGui::GetDefaultFontData(NULL, NULL, &png_data, &png_size); <..Upload texture to GPU..>
380  became: unsigned char* pixels; int width, height; io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height); <..Upload texture to GPU>; io.Fonts->TexId = YourTextureIdentifier;
381  you now more flexibility to load multiple TTF fonts and manage the texture buffer for internal needs.
382  it is now recommended that you sample the font texture with bilinear interpolation.
383  (1.30) - added texture identifier in ImDrawCmd passed to your render function (we can now render images). make sure to set io.Fonts->TexID.
384  (1.30) - removed IO.PixelCenterOffset (unnecessary, can be handled in user projection matrix)
385  (1.30) - removed ImGui::IsItemFocused() in favor of ImGui::IsItemActive() which handles all widgets
386  - 2014/12/10 (1.18) - removed SetNewWindowDefaultPos() in favor of new generic API SetNextWindowPos(pos, ImGuiSetCondition_FirstUseEver)
387  - 2014/11/28 (1.17) - moved IO.Font*** options to inside the IO.Font-> structure (FontYOffset, FontTexUvForWhite, FontBaseScale, FontFallbackGlyph)
388  - 2014/11/26 (1.17) - reworked syntax of IMGUI_ONCE_UPON_A_FRAME helper macro to increase compiler compatibility
389  - 2014/11/07 (1.15) - renamed IsHovered() to IsItemHovered()
390  - 2014/10/02 (1.14) - renamed IMGUI_INCLUDE_IMGUI_USER_CPP to IMGUI_INCLUDE_IMGUI_USER_INL and imgui_user.cpp to imgui_user.inl (more IDE friendly)
391  - 2014/09/25 (1.13) - removed 'text_end' parameter from IO.SetClipboardTextFn (the string is now always zero-terminated for simplicity)
392  - 2014/09/24 (1.12) - renamed SetFontScale() to SetWindowFontScale()
393  - 2014/09/24 (1.12) - moved IM_MALLOC/IM_REALLOC/IM_FREE preprocessor defines to IO.MemAllocFn/IO.MemReallocFn/IO.MemFreeFn
394  - 2014/08/30 (1.09) - removed IO.FontHeight (now computed automatically)
395  - 2014/08/30 (1.09) - moved IMGUI_FONT_TEX_UV_FOR_WHITE preprocessor define to IO.FontTexUvForWhite
396  - 2014/08/28 (1.09) - changed the behavior of IO.PixelCenterOffset following various rendering fixes
397 
398 
399  ISSUES & TODO-LIST
400  ==================
401  See TODO.txt
402 
403 
404  FREQUENTLY ASKED QUESTIONS (FAQ), TIPS
405  ======================================
406 
407  Q: How can I help?
408  A: - If you are experienced with Dear ImGui and C++, look at the github issues, or TODO.txt and see how you want/can help!
409  - Convince your company to fund development time! Individual users: you can also become a Patron (patreon.com/imgui) or donate on PayPal! See README.
410  - Disclose your usage of dear imgui via a dev blog post, a tweet, a screenshot, a mention somewhere etc.
411  You may post screenshot or links in the gallery threads (github.com/ocornut/imgui/issues/1269). Visuals are ideal as they inspire other programmers.
412  But even without visuals, disclosing your use of dear imgui help the library grow credibility, and help other teams and programmers with taking decisions.
413  - If you have issues or if you need to hack into the library, even if you don't expect any support it is useful that you share your issues (on github or privately).
414 
415  Q: How can I display an image? What is ImTextureID, how does it works?
416  A: ImTextureID is a void* used to pass renderer-agnostic texture references around until it hits your render function.
417  Dear ImGui knows nothing about what those bits represent, it just passes them around. It is up to you to decide what you want the void* to carry!
418  It could be an identifier to your OpenGL texture (cast GLuint to void*), a pointer to your custom engine material (cast MyMaterial* to void*), etc.
419  At the end of the chain, your renderer takes this void* to cast it back into whatever it needs to select a current texture to render.
420  Refer to examples applications, where each renderer (in a imgui_impl_xxxx.cpp file) is treating ImTextureID as a different thing.
421  (c++ tip: OpenGL uses integers to identify textures. You can safely store an integer into a void*, just cast it to void*, don't take it's address!)
422  To display a custom image/texture within an ImGui window, you may use ImGui::Image(), ImGui::ImageButton(), ImDrawList::AddImage() functions.
423  Dear ImGui will generate the geometry and draw calls using the ImTextureID that you passed and which your renderer can use.
424  You may call ImGui::ShowMetricsWindow() to explore active draw lists and visualize/understand how the draw data is generated.
425  It is your responsibility to get textures uploaded to your GPU.
426 
427  Q: Can I have multiple widgets with the same label? Can I have widget without a label?
428  A: Yes. A primer on labels and the ID stack...
429 
430  - Elements that are typically not clickable, such as Text() items don't need an ID.
431 
432  - Interactive widgets require state to be carried over multiple frames (most typically Dear ImGui often needs to remember what is
433  the "active" widget). to do so they need a unique ID. unique ID are typically derived from a string label, an integer index or a pointer.
434 
435  Button("OK"); // Label = "OK", ID = hash of "OK"
436  Button("Cancel"); // Label = "Cancel", ID = hash of "Cancel"
437 
438  - ID are uniquely scoped within windows, tree nodes, etc. so no conflict can happen if you have two buttons called "OK"
439  in two different windows or in two different locations of a tree.
440 
441  - If you have a same ID twice in the same location, you'll have a conflict:
442 
443  Button("OK");
444  Button("OK"); // ID collision! Both buttons will be treated as the same.
445 
446  Fear not! this is easy to solve and there are many ways to solve it!
447 
448  - When passing a label you can optionally specify extra unique ID information within string itself.
449  Use "##" to pass a complement to the ID that won't be visible to the end-user.
450  This helps solving the simple collision cases when you know which items are going to be created.
451 
452  Button("Play"); // Label = "Play", ID = hash of "Play"
453  Button("Play##foo1"); // Label = "Play", ID = hash of "Play##foo1" (different from above)
454  Button("Play##foo2"); // Label = "Play", ID = hash of "Play##foo2" (different from above)
455 
456  - If you want to completely hide the label, but still need an ID:
457 
458  Checkbox("##On", &b); // Label = "", ID = hash of "##On" (no label!)
459 
460  - Occasionally/rarely you might want change a label while preserving a constant ID. This allows you to animate labels.
461  For example you may want to include varying information in a window title bar, but windows are uniquely identified by their ID..
462  Use "###" to pass a label that isn't part of ID:
463 
464  Button("Hello###ID"; // Label = "Hello", ID = hash of "ID"
465  Button("World###ID"; // Label = "World", ID = hash of "ID" (same as above)
466 
467  sprintf(buf, "My game (%f FPS)###MyGame", fps);
468  Begin(buf); // Variable label, ID = hash of "MyGame"
469 
470  - Use PushID() / PopID() to create scopes and avoid ID conflicts within the same Window.
471  This is the most convenient way of distinguishing ID if you are iterating and creating many UI elements.
472  You can push a pointer, a string or an integer value. Remember that ID are formed from the concatenation of _everything_ in the ID stack!
473 
474  for (int i = 0; i < 100; i++)
475  {
476  PushID(i);
477  Button("Click"); // Label = "Click", ID = hash of integer + "label" (unique)
478  PopID();
479  }
480 
481  for (int i = 0; i < 100; i++)
482  {
483  MyObject* obj = Objects[i];
484  PushID(obj);
485  Button("Click"); // Label = "Click", ID = hash of pointer + "label" (unique)
486  PopID();
487  }
488 
489  for (int i = 0; i < 100; i++)
490  {
491  MyObject* obj = Objects[i];
492  PushID(obj->Name);
493  Button("Click"); // Label = "Click", ID = hash of string + "label" (unique)
494  PopID();
495  }
496 
497  - More example showing that you can stack multiple prefixes into the ID stack:
498 
499  Button("Click"); // Label = "Click", ID = hash of "Click"
500  PushID("node");
501  Button("Click"); // Label = "Click", ID = hash of "node" + "Click"
502  PushID(my_ptr);
503  Button("Click"); // Label = "Click", ID = hash of "node" + ptr + "Click"
504  PopID();
505  PopID();
506 
507  - Tree nodes implicitly creates a scope for you by calling PushID().
508 
509  Button("Click"); // Label = "Click", ID = hash of "Click"
510  if (TreeNode("node"))
511  {
512  Button("Click"); // Label = "Click", ID = hash of "node" + "Click"
513  TreePop();
514  }
515 
516  - When working with trees, ID are used to preserve the open/close state of each tree node.
517  Depending on your use cases you may want to use strings, indices or pointers as ID.
518  e.g. when displaying a single object that may change over time (dynamic 1-1 relationship), using a static string as ID will preserve your
519  node open/closed state when the targeted object change.
520  e.g. when displaying a list of objects, using indices or pointers as ID will preserve the node open/closed state differently.
521  experiment and see what makes more sense!
522 
523  Q: How can I tell when Dear ImGui wants my mouse/keyboard inputs VS when I can pass them to my application?
524  A: You can read the 'io.WantCaptureMouse'/'io.WantCaptureKeyboard'/'ioWantTextInput' flags from the ImGuiIO structure.
525  - When 'io.WantCaptureMouse' or 'io.WantCaptureKeyboard' flags are set you may want to discard/hide the inputs from the rest of your application.
526  - When 'io.WantTextInput' is set to may want to notify your OS to popup an on-screen keyboard, if available (e.g. on a mobile phone, or console OS).
527  Preferably read the flags after calling ImGui::NewFrame() to avoid them lagging by one frame. But reading those flags before calling NewFrame() is
528  also generally ok, as the bool toggles fairly rarely and you don't generally expect to interact with either Dear ImGui or your application during
529  the same frame when that transition occurs. Dear ImGui is tracking dragging and widget activity that may occur outside the boundary of a window,
530  so 'io.WantCaptureMouse' is more accurate and correct than checking if a window is hovered.
531  (Advanced note: text input releases focus on Return 'KeyDown', so the following Return 'KeyUp' event that your application receive will typically
532  have 'io.WantCaptureKeyboard=false'. Depending on your application logic it may or not be inconvenient. You might want to track which key-downs
533  were for Dear ImGui, e.g. with an array of bool, and filter out the corresponding key-ups.)
534 
535  Q: How can I load a different font than the default? (default is an embedded version of ProggyClean.ttf, rendered at size 13)
536  A: Use the font atlas to load the TTF/OTF file you want:
537  ImGuiIO& io = ImGui::GetIO();
538  io.Fonts->AddFontFromFileTTF("myfontfile.ttf", size_in_pixels);
539  io.Fonts->GetTexDataAsRGBA32() or GetTexDataAsAlpha8()
540 
541  New programmers: remember that in C/C++ and most programming languages if you want to use a backslash \ in a string literal you need to write a double backslash "\\":
542  io.Fonts->AddFontFromFileTTF("MyDataFolder\MyFontFile.ttf", size_in_pixels); // WRONG
543  io.Fonts->AddFontFromFileTTF("MyDataFolder\\MyFontFile.ttf", size_in_pixels); // CORRECT
544  io.Fonts->AddFontFromFileTTF("MyDataFolder/MyFontFile.ttf", size_in_pixels); // ALSO CORRECT
545 
546  Q: How can I easily use icons in my application?
547  A: The most convenient and practical way is to merge an icon font such as FontAwesome inside you main font. Then you can refer to icons within your
548  strings. Read 'How can I load multiple fonts?' and the file 'misc/fonts/README.txt' for instructions and useful header files.
549 
550  Q: How can I load multiple fonts?
551  A: Use the font atlas to pack them into a single texture:
552  (Read misc/fonts/README.txt and the code in ImFontAtlas for more details.)
553 
554  ImGuiIO& io = ImGui::GetIO();
555  ImFont* font0 = io.Fonts->AddFontDefault();
556  ImFont* font1 = io.Fonts->AddFontFromFileTTF("myfontfile.ttf", size_in_pixels);
557  ImFont* font2 = io.Fonts->AddFontFromFileTTF("myfontfile2.ttf", size_in_pixels);
558  io.Fonts->GetTexDataAsRGBA32() or GetTexDataAsAlpha8()
559  // the first loaded font gets used by default
560  // use ImGui::PushFont()/ImGui::PopFont() to change the font at runtime
561 
562  // Options
563  ImFontConfig config;
564  config.OversampleH = 3;
565  config.OversampleV = 1;
566  config.GlyphOffset.y -= 2.0f; // Move everything by 2 pixels up
567  config.GlyphExtraSpacing.x = 1.0f; // Increase spacing between characters
568  io.Fonts->LoadFromFileTTF("myfontfile.ttf", size_pixels, &config);
569 
570  // Combine multiple fonts into one (e.g. for icon fonts)
571  ImWchar ranges[] = { 0xf000, 0xf3ff, 0 };
572  ImFontConfig config;
573  config.MergeMode = true;
574  io.Fonts->AddFontDefault();
575  io.Fonts->LoadFromFileTTF("fontawesome-webfont.ttf", 16.0f, &config, ranges); // Merge icon font
576  io.Fonts->LoadFromFileTTF("myfontfile.ttf", size_pixels, NULL, &config, io.Fonts->GetGlyphRangesJapanese()); // Merge japanese glyphs
577 
578  Q: How can I display and input non-Latin characters such as Chinese, Japanese, Korean, Cyrillic?
579  A: When loading a font, pass custom Unicode ranges to specify the glyphs to load.
580 
581  // Add default Japanese ranges
582  io.Fonts->AddFontFromFileTTF("myfontfile.ttf", size_in_pixels, NULL, io.Fonts->GetGlyphRangesJapanese());
583 
584  // Or create your own custom ranges (e.g. for a game you can feed your entire game script and only build the characters the game need)
585  ImVector<ImWchar> ranges;
586  ImFontAtlas::GlyphRangesBuilder builder;
587  builder.AddText("Hello world"); // Add a string (here "Hello world" contains 7 unique characters)
588  builder.AddChar(0x7262); // Add a specific character
589  builder.AddRanges(io.Fonts->GetGlyphRangesJapanese()); // Add one of the default ranges
590  builder.BuildRanges(&ranges); // Build the final result (ordered ranges with all the unique characters submitted)
591  io.Fonts->AddFontFromFileTTF("myfontfile.ttf", size_in_pixels, NULL, ranges.Data);
592 
593  All your strings needs to use UTF-8 encoding. In C++11 you can encode a string literal in UTF-8 by using the u8"hello" syntax.
594  Specifying literal in your source code using a local code page (such as CP-923 for Japanese or CP-1251 for Cyrillic) will NOT work!
595  Otherwise you can convert yourself to UTF-8 or load text data from file already saved as UTF-8.
596 
597  Text input: it is up to your application to pass the right character code to io.AddInputCharacter(). The applications in examples/ are doing that.
598  For languages using IME, on Windows you can copy the Hwnd of your application to io.ImeWindowHandle.
599  The default implementation of io.ImeSetInputScreenPosFn() on Windows will set your IME position correctly.
600 
601  Q: How can I preserve my Dear ImGui context across reloading a DLL? (loss of the global/static variables)
602  A: Create your own context 'ctx = CreateContext()' + 'SetCurrentContext(ctx)' and your own font atlas 'ctx->GetIO().Fonts = new ImFontAtlas()'
603  so you don't rely on the default globals.
604 
605  Q: How can I use the drawing facilities without an ImGui window? (using ImDrawList API)
606  A: - You can create a dummy window. Call Begin() with NoTitleBar|NoResize|NoMove|NoScrollbar|NoSavedSettings|NoInputs flag,
607  push a ImGuiCol_WindowBg with zero alpha, then retrieve the ImDrawList* via GetWindowDrawList() and draw to it in any way you like.
608  - You can call ImGui::GetOverlayDrawList() and use this draw list to display contents over every other imgui windows.
609  - You can create your own ImDrawList instance. You'll need to initialize them ImGui::GetDrawListSharedData(), or create your own ImDrawListSharedData.
610 
611  Q: I integrated Dear ImGui in my engine and the text or lines are blurry..
612  A: In your Render function, try translating your projection matrix by (0.5f,0.5f) or (0.375f,0.375f).
613  Also make sure your orthographic projection matrix and io.DisplaySize matches your actual framebuffer dimension.
614 
615  Q: I integrated Dear ImGui in my engine and some elements are clipping or disappearing when I move windows around..
616  A: You are probably mishandling the clipping rectangles in your render function.
617  Rectangles provided by ImGui are defined as (x1=left,y1=top,x2=right,y2=bottom) and NOT as (x1,y1,width,height).
618 
619 
620  - tip: you can call Begin() multiple times with the same name during the same frame, it will keep appending to the same window.
621  this is also useful to set yourself in the context of another window (to get/set other settings)
622  - tip: you can create widgets without a Begin()/End() block, they will go in an implicit window called "Debug".
623  - tip: the ImGuiOnceUponAFrame helper will allow run the block of code only once a frame. You can use it to quickly add custom UI in the middle
624  of a deep nested inner loop in your code.
625  - tip: you can call Render() multiple times (e.g for VR renders).
626  - tip: call and read the ShowDemoWindow() code in imgui_demo.cpp for more example of how to use ImGui!
627 
628 */
629 
630 #if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS)
631 #define _CRT_SECURE_NO_WARNINGS
632 #endif
633 
635 #define IMGUI_DEFINE_MATH_OPERATORS
637 
638 #include <ctype.h> // toupper, isprint
639 #include <stdlib.h> // NULL, malloc, free, qsort, atoi
640 #include <stdio.h> // vsnprintf, sscanf, printf
641 #if defined(_MSC_VER) && _MSC_VER <= 1500 // MSVC 2008 or earlier
642 #include <stddef.h> // intptr_t
643 #else
644 #include <stdint.h> // intptr_t
645 #endif
646 
647 #define IMGUI_DEBUG_NAV_SCORING 0
648 #define IMGUI_DEBUG_NAV_RECTS 0
649 
650 // Visual Studio warnings
651 #ifdef _MSC_VER
652 #pragma warning (disable: 4127) // condition expression is constant
653 #pragma warning (disable: 4505) // unreferenced local function has been removed (stb stuff)
654 #pragma warning (disable: 4996) // 'This function or variable may be unsafe': strcpy, strdup, sprintf, vsnprintf, sscanf, fopen
655 #endif
656 
657 // Clang warnings with -Weverything
658 #ifdef __clang__
659 #pragma clang diagnostic ignored "-Wunknown-pragmas" // warning : unknown warning group '-Wformat-pedantic *' // not all warnings are known by all clang versions.. so ignoring warnings triggers new warnings on some configuration. great!
660 #pragma clang diagnostic ignored "-Wold-style-cast" // warning : use of old-style cast // yes, they are more terse.
661 #pragma clang diagnostic ignored "-Wfloat-equal" // warning : comparing floating point with == or != is unsafe // storing and comparing against same constants (typically 0.0f) is ok.
662 #pragma clang diagnostic ignored "-Wformat-nonliteral" // warning : format string is not a string literal // passing non-literal to vsnformat(). yes, user passing incorrect format strings can crash the code.
663 #pragma clang diagnostic ignored "-Wexit-time-destructors" // warning : declaration requires an exit-time destructor // exit-time destruction order is undefined. if MemFree() leads to users code that has been disabled before exit it might cause problems. ImGui coding style welcomes static/globals.
664 #pragma clang diagnostic ignored "-Wglobal-constructors" // warning : declaration requires a global destructor // similar to above, not sure what the exact difference it.
665 #pragma clang diagnostic ignored "-Wsign-conversion" // warning : implicit conversion changes signedness //
666 #pragma clang diagnostic ignored "-Wformat-pedantic" // warning : format specifies type 'void *' but the argument has type 'xxxx *' // unreasonable, would lead to casting every %p arg to void*. probably enabled by -pedantic.
667 #pragma clang diagnostic ignored "-Wint-to-void-pointer-cast" // warning : cast to 'void *' from smaller integer type 'int' //
668 #elif defined(__GNUC__)
669 #pragma GCC diagnostic ignored "-Wunused-function" // warning: 'xxxx' defined but not used
670 #pragma GCC diagnostic ignored "-Wint-to-pointer-cast" // warning: cast to pointer from integer of different size
671 #pragma GCC diagnostic ignored "-Wformat" // warning: format '%p' expects argument of type 'void*', but argument 6 has type 'ImGuiWindow*'
672 #pragma GCC diagnostic ignored "-Wdouble-promotion" // warning: implicit conversion from 'float' to 'double' when passing argument to function
673 #pragma GCC diagnostic ignored "-Wconversion" // warning: conversion to 'xxxx' from 'xxxx' may alter its value
674 #pragma GCC diagnostic ignored "-Wcast-qual" // warning: cast from type 'xxxx' to type 'xxxx' casts away qualifiers
675 #pragma GCC diagnostic ignored "-Wformat-nonliteral" // warning: format not a string literal, format string not checked
676 #pragma GCC diagnostic ignored "-Wstrict-overflow" // warning: assuming signed overflow does not occur when assuming that (X - c) > X is always false
677 #endif
678 
679 // Enforce cdecl calling convention for functions called by the standard library, in case compilation settings changed the default to e.g. __vectorcall
680 #ifdef _MSC_VER
681 #define IMGUI_CDECL __cdecl
682 #else
683 #define IMGUI_CDECL
684 #endif
685 
686 //-------------------------------------------------------------------------
687 // Forward Declarations
688 //-------------------------------------------------------------------------
689 
690 static bool IsKeyPressedMap(ImGuiKey key, bool repeat = true);
691 
692 static ImFont* GetDefaultFont();
693 static void SetCurrentWindow(ImGuiWindow* window);
694 static void SetWindowScrollX(ImGuiWindow* window, float new_scroll_x);
695 static void SetWindowScrollY(ImGuiWindow* window, float new_scroll_y);
696 static void SetWindowPos(ImGuiWindow* window, const ImVec2& pos, ImGuiCond cond);
697 static void SetWindowSize(ImGuiWindow* window, const ImVec2& size, ImGuiCond cond);
698 static void SetWindowCollapsed(ImGuiWindow* window, bool collapsed, ImGuiCond cond);
701 static void CheckStacksSize(ImGuiWindow* window, bool write);
703 
704 static void AddDrawListToDrawData(ImVector<ImDrawList*>* out_list, ImDrawList* draw_list);
705 static void AddWindowToDrawData(ImVector<ImDrawList*>* out_list, ImGuiWindow* window);
706 static void AddWindowToSortedBuffer(ImVector<ImGuiWindow*>* out_sorted_windows, ImGuiWindow* window);
707 
708 static ImGuiWindowSettings* AddWindowSettings(const char* name);
709 
710 static void LoadIniSettingsFromDisk(const char* ini_filename);
711 static void LoadIniSettingsFromMemory(const char* buf);
712 static void SaveIniSettingsToDisk(const char* ini_filename);
713 static void SaveIniSettingsToMemory(ImVector<char>& out_buf);
714 static void MarkIniSettingsDirty(ImGuiWindow* window);
715 
716 static ImRect GetViewportRect();
717 
718 static void ClosePopupToLevel(int remaining);
720 
721 static bool InputTextFilterCharacter(unsigned int* p_char, ImGuiInputTextFlags flags, ImGuiTextEditCallback callback, void* user_data);
722 static int InputTextCalcTextLenAndLineCount(const char* text_begin, const char** out_text_end);
723 static ImVec2 InputTextCalcTextSizeW(const ImWchar* text_begin, const ImWchar* text_end, const ImWchar** remaining = NULL, ImVec2* out_offset = NULL, bool stop_on_new_line = false);
724 
725 static inline void DataTypeFormatString(ImGuiDataType data_type, void* data_ptr, const char* display_format, char* buf, int buf_size);
726 static inline void DataTypeFormatString(ImGuiDataType data_type, void* data_ptr, int decimal_precision, char* buf, int buf_size);
727 static void DataTypeApplyOp(ImGuiDataType data_type, int op, void* value1, const void* value2);
728 static bool DataTypeApplyOpFromText(const char* buf, const char* initial_value_buf, ImGuiDataType data_type, void* data_ptr, const char* scalar_format);
729 
730 namespace ImGui
731 {
732 static void NavUpdate();
733 static void NavUpdateWindowing();
734 static void NavProcessItem(ImGuiWindow* window, const ImRect& nav_bb, const ImGuiID id);
735 
736 static void UpdateMovingWindow();
737 static void UpdateManualResize(ImGuiWindow* window, const ImVec2& size_auto_fit, int* border_held, int resize_grip_count, ImU32 resize_grip_col[4]);
738 static void FocusFrontMostActiveWindow(ImGuiWindow* ignore_window);
739 }
740 
741 //-----------------------------------------------------------------------------
742 // Platform dependent default implementations
743 //-----------------------------------------------------------------------------
744 
745 static const char* GetClipboardTextFn_DefaultImpl(void* user_data);
746 static void SetClipboardTextFn_DefaultImpl(void* user_data, const char* text);
747 static void ImeSetInputScreenPosFn_DefaultImpl(int x, int y);
748 
749 //-----------------------------------------------------------------------------
750 // Context
751 //-----------------------------------------------------------------------------
752 
753 // Current context pointer. Implicitely used by all ImGui functions. Always assumed to be != NULL.
754 // CreateContext() will automatically set this pointer if it is NULL. Change to a different context by calling ImGui::SetCurrentContext().
755 // If you use DLL hotreloading you might need to call SetCurrentContext() after reloading code from this file.
756 // ImGui functions are not thread-safe because of this pointer. If you want thread-safety to allow N threads to access N different contexts, you can:
757 // - Change this variable to use thread local storage. You may #define GImGui in imconfig.h for that purpose. Future development aim to make this context pointer explicit to all calls. Also read https://github.com/ocornut/imgui/issues/586
758 // - Having multiple instances of the ImGui code compiled inside different namespace (easiest/safest, if you have a finite number of contexts)
759 #ifndef GImGui
761 #endif
762 
763 // Memory Allocator functions. Use SetAllocatorFunctions() to change them.
764 // If you use DLL hotreloading you might need to call SetAllocatorFunctions() after reloading code from this file.
765 // Otherwise, you probably don't want to modify them mid-program, and if you use global/static e.g. ImVector<> instances you may need to keep them accessible during program destruction.
766 #ifndef IMGUI_DISABLE_DEFAULT_ALLOCATORS
767 static void* MallocWrapper(size_t size, void* user_data) { (void)user_data; return malloc(size); }
768 static void FreeWrapper(void* ptr, void* user_data) { (void)user_data; free(ptr); }
769 #else
770 static void* MallocWrapper(size_t size, void* user_data) { (void)user_data; (void)size; IM_ASSERT(0); return NULL; }
771 static void FreeWrapper(void* ptr, void* user_data) { (void)user_data; (void)ptr; IM_ASSERT(0); }
772 #endif
773 
774 static void* (*GImAllocatorAllocFunc)(size_t size, void* user_data) = MallocWrapper;
775 static void (*GImAllocatorFreeFunc)(void* ptr, void* user_data) = FreeWrapper;
776 static void* GImAllocatorUserData = NULL;
778 
779 //-----------------------------------------------------------------------------
780 // User facing structures
781 //-----------------------------------------------------------------------------
782 
784 {
785  Alpha = 1.0f; // Global alpha applies to everything in ImGui
786  WindowPadding = ImVec2(8,8); // Padding within a window
787  WindowRounding = 7.0f; // Radius of window corners rounding. Set to 0.0f to have rectangular windows
788  WindowBorderSize = 1.0f; // Thickness of border around windows. Generally set to 0.0f or 1.0f. Other values not well tested.
789  WindowMinSize = ImVec2(32,32); // Minimum window size
790  WindowTitleAlign = ImVec2(0.0f,0.5f);// Alignment for title bar text
791  ChildRounding = 0.0f; // Radius of child window corners rounding. Set to 0.0f to have rectangular child windows
792  ChildBorderSize = 1.0f; // Thickness of border around child windows. Generally set to 0.0f or 1.0f. Other values not well tested.
793  PopupRounding = 0.0f; // Radius of popup window corners rounding. Set to 0.0f to have rectangular child windows
794  PopupBorderSize = 1.0f; // Thickness of border around popup or tooltip windows. Generally set to 0.0f or 1.0f. Other values not well tested.
795  FramePadding = ImVec2(4,3); // Padding within a framed rectangle (used by most widgets)
796  FrameRounding = 0.0f; // Radius of frame corners rounding. Set to 0.0f to have rectangular frames (used by most widgets).
797  FrameBorderSize = 0.0f; // Thickness of border around frames. Generally set to 0.0f or 1.0f. Other values not well tested.
798  ItemSpacing = ImVec2(8,4); // Horizontal and vertical spacing between widgets/lines
799  ItemInnerSpacing = ImVec2(4,4); // Horizontal and vertical spacing between within elements of a composed widget (e.g. a slider and its label)
800  TouchExtraPadding = ImVec2(0,0); // Expand reactive bounding box for touch-based system where touch position is not accurate enough. Unfortunately we don't sort widgets so priority on overlap will always be given to the first widget. So don't grow this too much!
801  IndentSpacing = 21.0f; // Horizontal spacing when e.g. entering a tree node. Generally == (FontSize + FramePadding.x*2).
802  ColumnsMinSpacing = 6.0f; // Minimum horizontal spacing between two columns
803  ScrollbarSize = 16.0f; // Width of the vertical scrollbar, Height of the horizontal scrollbar
804  ScrollbarRounding = 9.0f; // Radius of grab corners rounding for scrollbar
805  GrabMinSize = 10.0f; // Minimum width/height of a grab box for slider/scrollbar
806  GrabRounding = 0.0f; // Radius of grabs corners rounding. Set to 0.0f to have rectangular slider grabs.
807  ButtonTextAlign = ImVec2(0.5f,0.5f);// Alignment of button text when button is larger than text.
808  DisplayWindowPadding = ImVec2(22,22); // Window positions are clamped to be visible within the display area by at least this amount. Only covers regular windows.
809  DisplaySafeAreaPadding = ImVec2(4,4); // If you cannot see the edge of your screen (e.g. on a TV) increase the safe area padding. Covers popups/tooltips as well regular windows.
810  MouseCursorScale = 1.0f; // Scale software rendered mouse cursor (when io.MouseDrawCursor is enabled). May be removed later.
811  AntiAliasedLines = true; // Enable anti-aliasing on lines/borders. Disable if you are really short on CPU/GPU.
812  AntiAliasedFill = true; // Enable anti-aliasing on filled shapes (rounded rectangles, circles, etc.)
813  CurveTessellationTol = 1.25f; // Tessellation tolerance when using PathBezierCurveTo() without a specific number of segments. Decrease for highly tessellated curves (higher quality, more polygons), increase to reduce quality.
814 
816 }
817 
818 // To scale your entire UI (e.g. if you want your app to use High DPI or generally be DPI aware) you may use this helper function. Scaling the fonts is done separately and is up to you.
819 // Important: This operation is lossy because we round all sizes to integer. If you need to change your scale multiples, call this over a freshly initialized ImGuiStyle structure rather than scaling multiple times.
820 void ImGuiStyle::ScaleAllSizes(float scale_factor)
821 {
822  WindowPadding = ImFloor(WindowPadding * scale_factor);
823  WindowRounding = ImFloor(WindowRounding * scale_factor);
824  WindowMinSize = ImFloor(WindowMinSize * scale_factor);
825  ChildRounding = ImFloor(ChildRounding * scale_factor);
826  PopupRounding = ImFloor(PopupRounding * scale_factor);
827  FramePadding = ImFloor(FramePadding * scale_factor);
828  FrameRounding = ImFloor(FrameRounding * scale_factor);
829  ItemSpacing = ImFloor(ItemSpacing * scale_factor);
830  ItemInnerSpacing = ImFloor(ItemInnerSpacing * scale_factor);
831  TouchExtraPadding = ImFloor(TouchExtraPadding * scale_factor);
832  IndentSpacing = ImFloor(IndentSpacing * scale_factor);
833  ColumnsMinSpacing = ImFloor(ColumnsMinSpacing * scale_factor);
834  ScrollbarSize = ImFloor(ScrollbarSize * scale_factor);
835  ScrollbarRounding = ImFloor(ScrollbarRounding * scale_factor);
836  GrabMinSize = ImFloor(GrabMinSize * scale_factor);
837  GrabRounding = ImFloor(GrabRounding * scale_factor);
840  MouseCursorScale = ImFloor(MouseCursorScale * scale_factor);
841 }
842 
844 {
845  // Most fields are initialized with zero
846  memset(this, 0, sizeof(*this));
847 
848  // Settings
849  DisplaySize = ImVec2(-1.0f, -1.0f);
850  DeltaTime = 1.0f/60.0f;
851  ConfigFlags = 0x00;
852  IniSavingRate = 5.0f;
853  IniFilename = "imgui.ini";
854  LogFilename = "imgui_log.txt";
855  MouseDoubleClickTime = 0.30f;
857  for (int i = 0; i < ImGuiKey_COUNT; i++)
858  KeyMap[i] = -1;
859  KeyRepeatDelay = 0.250f;
860  KeyRepeatRate = 0.050f;
861  UserData = NULL;
862 
863  Fonts = NULL;
864  FontGlobalScale = 1.0f;
865  FontDefault = NULL;
866  FontAllowUserScaling = false;
867  DisplayFramebufferScale = ImVec2(1.0f, 1.0f);
869 
870  // Advanced/subtle behaviors
871 #ifdef __APPLE__
872  OptMacOSXBehaviors = true; // Set Mac OS X style defaults based on __APPLE__ compile time flag
873 #else
874  OptMacOSXBehaviors = false;
875 #endif
876  OptCursorBlink = true;
877 
878  // Settings (User Functions)
879  GetClipboardTextFn = GetClipboardTextFn_DefaultImpl; // Platform dependent default implementations
884 
885 #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
887 #endif
888 
889  // Input (NB: we already have memset zero the entire structure)
892  MouseDragThreshold = 6.0f;
893  for (int i = 0; i < IM_ARRAYSIZE(MouseDownDuration); i++) MouseDownDuration[i] = MouseDownDurationPrev[i] = -1.0f;
894  for (int i = 0; i < IM_ARRAYSIZE(KeysDownDuration); i++) KeysDownDuration[i] = KeysDownDurationPrev[i] = -1.0f;
895  for (int i = 0; i < IM_ARRAYSIZE(NavInputsDownDuration); i++) NavInputsDownDuration[i] = -1.0f;
896 }
897 
898 // Pass in translated ASCII characters for text input.
899 // - with glfw you can get those from the callback set in glfwSetCharCallback()
900 // - on Windows you can get those using ToAscii+keyboard state, or via the WM_CHAR message
902 {
903  const int n = ImStrlenW(InputCharacters);
904  if (n + 1 < IM_ARRAYSIZE(InputCharacters))
905  {
906  InputCharacters[n] = c;
907  InputCharacters[n+1] = '\0';
908  }
909 }
910 
911 void ImGuiIO::AddInputCharactersUTF8(const char* utf8_chars)
912 {
913  // We can't pass more wchars than ImGuiIO::InputCharacters[] can hold so don't convert more
914  const int wchars_buf_len = sizeof(ImGuiIO::InputCharacters) / sizeof(ImWchar);
915  ImWchar wchars[wchars_buf_len];
916  ImTextStrFromUtf8(wchars, wchars_buf_len, utf8_chars, NULL);
917  for (int i = 0; i < wchars_buf_len && wchars[i] != 0; i++)
918  AddInputCharacter(wchars[i]);
919 }
920 
921 //-----------------------------------------------------------------------------
922 // HELPERS
923 //-----------------------------------------------------------------------------
924 
925 #define IM_F32_TO_INT8_UNBOUND(_VAL) ((int)((_VAL) * 255.0f + ((_VAL)>=0 ? 0.5f : -0.5f))) // Unsaturated, for display purpose
926 #define IM_F32_TO_INT8_SAT(_VAL) ((int)(ImSaturate(_VAL) * 255.0f + 0.5f)) // Saturated, always output 0..255
927 
928 ImVec2 ImLineClosestPoint(const ImVec2& a, const ImVec2& b, const ImVec2& p)
929 {
930  ImVec2 ap = p - a;
931  ImVec2 ab_dir = b - a;
932  float dot = ap.x * ab_dir.x + ap.y * ab_dir.y;
933  if (dot < 0.0f)
934  return a;
935  float ab_len_sqr = ab_dir.x * ab_dir.x + ab_dir.y * ab_dir.y;
936  if (dot > ab_len_sqr)
937  return b;
938  return a + ab_dir * dot / ab_len_sqr;
939 }
940 
941 bool ImTriangleContainsPoint(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& p)
942 {
943  bool b1 = ((p.x - b.x) * (a.y - b.y) - (p.y - b.y) * (a.x - b.x)) < 0.0f;
944  bool b2 = ((p.x - c.x) * (b.y - c.y) - (p.y - c.y) * (b.x - c.x)) < 0.0f;
945  bool b3 = ((p.x - a.x) * (c.y - a.y) - (p.y - a.y) * (c.x - a.x)) < 0.0f;
946  return ((b1 == b2) && (b2 == b3));
947 }
948 
949 void ImTriangleBarycentricCoords(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& p, float& out_u, float& out_v, float& out_w)
950 {
951  ImVec2 v0 = b - a;
952  ImVec2 v1 = c - a;
953  ImVec2 v2 = p - a;
954  const float denom = v0.x * v1.y - v1.x * v0.y;
955  out_v = (v2.x * v1.y - v1.x * v2.y) / denom;
956  out_w = (v0.x * v2.y - v2.x * v0.y) / denom;
957  out_u = 1.0f - out_v - out_w;
958 }
959 
960 ImVec2 ImTriangleClosestPoint(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& p)
961 {
962  ImVec2 proj_ab = ImLineClosestPoint(a, b, p);
963  ImVec2 proj_bc = ImLineClosestPoint(b, c, p);
964  ImVec2 proj_ca = ImLineClosestPoint(c, a, p);
965  float dist2_ab = ImLengthSqr(p - proj_ab);
966  float dist2_bc = ImLengthSqr(p - proj_bc);
967  float dist2_ca = ImLengthSqr(p - proj_ca);
968  float m = ImMin(dist2_ab, ImMin(dist2_bc, dist2_ca));
969  if (m == dist2_ab)
970  return proj_ab;
971  if (m == dist2_bc)
972  return proj_bc;
973  return proj_ca;
974 }
975 
976 int ImStricmp(const char* str1, const char* str2)
977 {
978  int d;
979  while ((d = toupper(*str2) - toupper(*str1)) == 0 && *str1) { str1++; str2++; }
980  return d;
981 }
982 
983 int ImStrnicmp(const char* str1, const char* str2, size_t count)
984 {
985  int d = 0;
986  while (count > 0 && (d = toupper(*str2) - toupper(*str1)) == 0 && *str1) { str1++; str2++; count--; }
987  return d;
988 }
989 
990 void ImStrncpy(char* dst, const char* src, size_t count)
991 {
992  if (count < 1) return;
993  strncpy(dst, src, count);
994  dst[count-1] = 0;
995 }
996 
997 char* ImStrdup(const char *str)
998 {
999  size_t len = strlen(str) + 1;
1000  void* buf = ImGui::MemAlloc(len);
1001  return (char*)memcpy(buf, (const void*)str, len);
1002 }
1003 
1004 char* ImStrchrRange(const char* str, const char* str_end, char c)
1005 {
1006  for ( ; str < str_end; str++)
1007  if (*str == c)
1008  return (char*)str;
1009  return NULL;
1010 }
1011 
1012 int ImStrlenW(const ImWchar* str)
1013 {
1014  int n = 0;
1015  while (*str++) n++;
1016  return n;
1017 }
1018 
1019 const ImWchar* ImStrbolW(const ImWchar* buf_mid_line, const ImWchar* buf_begin) // find beginning-of-line
1020 {
1021  while (buf_mid_line > buf_begin && buf_mid_line[-1] != '\n')
1022  buf_mid_line--;
1023  return buf_mid_line;
1024 }
1025 
1026 const char* ImStristr(const char* haystack, const char* haystack_end, const char* needle, const char* needle_end)
1027 {
1028  if (!needle_end)
1029  needle_end = needle + strlen(needle);
1030 
1031  const char un0 = (char)toupper(*needle);
1032  while ((!haystack_end && *haystack) || (haystack_end && haystack < haystack_end))
1033  {
1034  if (toupper(*haystack) == un0)
1035  {
1036  const char* b = needle + 1;
1037  for (const char* a = haystack + 1; b < needle_end; a++, b++)
1038  if (toupper(*a) != toupper(*b))
1039  break;
1040  if (b == needle_end)
1041  return haystack;
1042  }
1043  haystack++;
1044  }
1045  return NULL;
1046 }
1047 
1048 static const char* ImAtoi(const char* src, int* output)
1049 {
1050  int negative = 0;
1051  if (*src == '-') { negative = 1; src++; }
1052  if (*src == '+') { src++; }
1053  int v = 0;
1054  while (*src >= '0' && *src <= '9')
1055  v = (v * 10) + (*src++ - '0');
1056  *output = negative ? -v : v;
1057  return src;
1058 }
1059 
1060 // A) MSVC version appears to return -1 on overflow, whereas glibc appears to return total count (which may be >= buf_size).
1061 // Ideally we would test for only one of those limits at runtime depending on the behavior the vsnprintf(), but trying to deduct it at compile time sounds like a pandora can of worm.
1062 // B) When buf==NULL vsnprintf() will return the output size.
1063 #ifndef IMGUI_DISABLE_FORMAT_STRING_FUNCTIONS
1064 int ImFormatString(char* buf, size_t buf_size, const char* fmt, ...)
1065 {
1066  va_list args;
1067  va_start(args, fmt);
1068  int w = vsnprintf(buf, buf_size, fmt, args);
1069  va_end(args);
1070  if (buf == NULL)
1071  return w;
1072  if (w == -1 || w >= (int)buf_size)
1073  w = (int)buf_size - 1;
1074  buf[w] = 0;
1075  return w;
1076 }
1077 
1078 int ImFormatStringV(char* buf, size_t buf_size, const char* fmt, va_list args)
1079 {
1080  int w = vsnprintf(buf, buf_size, fmt, args);
1081  if (buf == NULL)
1082  return w;
1083  if (w == -1 || w >= (int)buf_size)
1084  w = (int)buf_size - 1;
1085  buf[w] = 0;
1086  return w;
1087 }
1088 #endif // #ifdef IMGUI_DISABLE_FORMAT_STRING_FUNCTIONS
1089 
1090 // Pass data_size==0 for zero-terminated strings
1091 // FIXME-OPT: Replace with e.g. FNV1a hash? CRC32 pretty much randomly access 1KB. Need to do proper measurements.
1092 ImU32 ImHash(const void* data, int data_size, ImU32 seed)
1093 {
1094  static ImU32 crc32_lut[256] = { 0 };
1095  if (!crc32_lut[1])
1096  {
1097  const ImU32 polynomial = 0xEDB88320;
1098  for (ImU32 i = 0; i < 256; i++)
1099  {
1100  ImU32 crc = i;
1101  for (ImU32 j = 0; j < 8; j++)
1102  crc = (crc >> 1) ^ (ImU32(-int(crc & 1)) & polynomial);
1103  crc32_lut[i] = crc;
1104  }
1105  }
1106 
1107  seed = ~seed;
1108  ImU32 crc = seed;
1109  const unsigned char* current = (const unsigned char*)data;
1110 
1111  if (data_size > 0)
1112  {
1113  // Known size
1114  while (data_size--)
1115  crc = (crc >> 8) ^ crc32_lut[(crc & 0xFF) ^ *current++];
1116  }
1117  else
1118  {
1119  // Zero-terminated string
1120  while (unsigned char c = *current++)
1121  {
1122  // We support a syntax of "label###id" where only "###id" is included in the hash, and only "label" gets displayed.
1123  // Because this syntax is rarely used we are optimizing for the common case.
1124  // - If we reach ### in the string we discard the hash so far and reset to the seed.
1125  // - We don't do 'current += 2; continue;' after handling ### to keep the code smaller.
1126  if (c == '#' && current[0] == '#' && current[1] == '#')
1127  crc = seed;
1128  crc = (crc >> 8) ^ crc32_lut[(crc & 0xFF) ^ c];
1129  }
1130  }
1131  return ~crc;
1132 }
1133 
1134 //-----------------------------------------------------------------------------
1135 // ImText* helpers
1136 //-----------------------------------------------------------------------------
1137 
1138 // Convert UTF-8 to 32-bits character, process single character input.
1139 // Based on stb_from_utf8() from github.com/nothings/stb/
1140 // We handle UTF-8 decoding error by skipping forward.
1141 int ImTextCharFromUtf8(unsigned int* out_char, const char* in_text, const char* in_text_end)
1142 {
1143  unsigned int c = (unsigned int)-1;
1144  const unsigned char* str = (const unsigned char*)in_text;
1145  if (!(*str & 0x80))
1146  {
1147  c = (unsigned int)(*str++);
1148  *out_char = c;
1149  return 1;
1150  }
1151  if ((*str & 0xe0) == 0xc0)
1152  {
1153  *out_char = 0xFFFD; // will be invalid but not end of string
1154  if (in_text_end && in_text_end - (const char*)str < 2) return 1;
1155  if (*str < 0xc2) return 2;
1156  c = (unsigned int)((*str++ & 0x1f) << 6);
1157  if ((*str & 0xc0) != 0x80) return 2;
1158  c += (*str++ & 0x3f);
1159  *out_char = c;
1160  return 2;
1161  }
1162  if ((*str & 0xf0) == 0xe0)
1163  {
1164  *out_char = 0xFFFD; // will be invalid but not end of string
1165  if (in_text_end && in_text_end - (const char*)str < 3) return 1;
1166  if (*str == 0xe0 && (str[1] < 0xa0 || str[1] > 0xbf)) return 3;
1167  if (*str == 0xed && str[1] > 0x9f) return 3; // str[1] < 0x80 is checked below
1168  c = (unsigned int)((*str++ & 0x0f) << 12);
1169  if ((*str & 0xc0) != 0x80) return 3;
1170  c += (unsigned int)((*str++ & 0x3f) << 6);
1171  if ((*str & 0xc0) != 0x80) return 3;
1172  c += (*str++ & 0x3f);
1173  *out_char = c;
1174  return 3;
1175  }
1176  if ((*str & 0xf8) == 0xf0)
1177  {
1178  *out_char = 0xFFFD; // will be invalid but not end of string
1179  if (in_text_end && in_text_end - (const char*)str < 4) return 1;
1180  if (*str > 0xf4) return 4;
1181  if (*str == 0xf0 && (str[1] < 0x90 || str[1] > 0xbf)) return 4;
1182  if (*str == 0xf4 && str[1] > 0x8f) return 4; // str[1] < 0x80 is checked below
1183  c = (unsigned int)((*str++ & 0x07) << 18);
1184  if ((*str & 0xc0) != 0x80) return 4;
1185  c += (unsigned int)((*str++ & 0x3f) << 12);
1186  if ((*str & 0xc0) != 0x80) return 4;
1187  c += (unsigned int)((*str++ & 0x3f) << 6);
1188  if ((*str & 0xc0) != 0x80) return 4;
1189  c += (*str++ & 0x3f);
1190  // utf-8 encodings of values used in surrogate pairs are invalid
1191  if ((c & 0xFFFFF800) == 0xD800) return 4;
1192  *out_char = c;
1193  return 4;
1194  }
1195  *out_char = 0;
1196  return 0;
1197 }
1198 
1199 int ImTextStrFromUtf8(ImWchar* buf, int buf_size, const char* in_text, const char* in_text_end, const char** in_text_remaining)
1200 {
1201  ImWchar* buf_out = buf;
1202  ImWchar* buf_end = buf + buf_size;
1203  while (buf_out < buf_end-1 && (!in_text_end || in_text < in_text_end) && *in_text)
1204  {
1205  unsigned int c;
1206  in_text += ImTextCharFromUtf8(&c, in_text, in_text_end);
1207  if (c == 0)
1208  break;
1209  if (c < 0x10000) // FIXME: Losing characters that don't fit in 2 bytes
1210  *buf_out++ = (ImWchar)c;
1211  }
1212  *buf_out = 0;
1213  if (in_text_remaining)
1214  *in_text_remaining = in_text;
1215  return (int)(buf_out - buf);
1216 }
1217 
1218 int ImTextCountCharsFromUtf8(const char* in_text, const char* in_text_end)
1219 {
1220  int char_count = 0;
1221  while ((!in_text_end || in_text < in_text_end) && *in_text)
1222  {
1223  unsigned int c;
1224  in_text += ImTextCharFromUtf8(&c, in_text, in_text_end);
1225  if (c == 0)
1226  break;
1227  if (c < 0x10000)
1228  char_count++;
1229  }
1230  return char_count;
1231 }
1232 
1233 // Based on stb_to_utf8() from github.com/nothings/stb/
1234 static inline int ImTextCharToUtf8(char* buf, int buf_size, unsigned int c)
1235 {
1236  if (c < 0x80)
1237  {
1238  buf[0] = (char)c;
1239  return 1;
1240  }
1241  if (c < 0x800)
1242  {
1243  if (buf_size < 2) return 0;
1244  buf[0] = (char)(0xc0 + (c >> 6));
1245  buf[1] = (char)(0x80 + (c & 0x3f));
1246  return 2;
1247  }
1248  if (c >= 0xdc00 && c < 0xe000)
1249  {
1250  return 0;
1251  }
1252  if (c >= 0xd800 && c < 0xdc00)
1253  {
1254  if (buf_size < 4) return 0;
1255  buf[0] = (char)(0xf0 + (c >> 18));
1256  buf[1] = (char)(0x80 + ((c >> 12) & 0x3f));
1257  buf[2] = (char)(0x80 + ((c >> 6) & 0x3f));
1258  buf[3] = (char)(0x80 + ((c ) & 0x3f));
1259  return 4;
1260  }
1261  //else if (c < 0x10000)
1262  {
1263  if (buf_size < 3) return 0;
1264  buf[0] = (char)(0xe0 + (c >> 12));
1265  buf[1] = (char)(0x80 + ((c>> 6) & 0x3f));
1266  buf[2] = (char)(0x80 + ((c ) & 0x3f));
1267  return 3;
1268  }
1269 }
1270 
1271 static inline int ImTextCountUtf8BytesFromChar(unsigned int c)
1272 {
1273  if (c < 0x80) return 1;
1274  if (c < 0x800) return 2;
1275  if (c >= 0xdc00 && c < 0xe000) return 0;
1276  if (c >= 0xd800 && c < 0xdc00) return 4;
1277  return 3;
1278 }
1279 
1280 int ImTextStrToUtf8(char* buf, int buf_size, const ImWchar* in_text, const ImWchar* in_text_end)
1281 {
1282  char* buf_out = buf;
1283  const char* buf_end = buf + buf_size;
1284  while (buf_out < buf_end-1 && (!in_text_end || in_text < in_text_end) && *in_text)
1285  {
1286  unsigned int c = (unsigned int)(*in_text++);
1287  if (c < 0x80)
1288  *buf_out++ = (char)c;
1289  else
1290  buf_out += ImTextCharToUtf8(buf_out, (int)(buf_end-buf_out-1), c);
1291  }
1292  *buf_out = 0;
1293  return (int)(buf_out - buf);
1294 }
1295 
1296 int ImTextCountUtf8BytesFromStr(const ImWchar* in_text, const ImWchar* in_text_end)
1297 {
1298  int bytes_count = 0;
1299  while ((!in_text_end || in_text < in_text_end) && *in_text)
1300  {
1301  unsigned int c = (unsigned int)(*in_text++);
1302  if (c < 0x80)
1303  bytes_count++;
1304  else
1305  bytes_count += ImTextCountUtf8BytesFromChar(c);
1306  }
1307  return bytes_count;
1308 }
1309 
1311 {
1312  float s = 1.0f/255.0f;
1313  return ImVec4(
1314  ((in >> IM_COL32_R_SHIFT) & 0xFF) * s,
1315  ((in >> IM_COL32_G_SHIFT) & 0xFF) * s,
1316  ((in >> IM_COL32_B_SHIFT) & 0xFF) * s,
1317  ((in >> IM_COL32_A_SHIFT) & 0xFF) * s);
1318 }
1319 
1321 {
1322  ImU32 out;
1324  out |= ((ImU32)IM_F32_TO_INT8_SAT(in.y)) << IM_COL32_G_SHIFT;
1325  out |= ((ImU32)IM_F32_TO_INT8_SAT(in.z)) << IM_COL32_B_SHIFT;
1326  out |= ((ImU32)IM_F32_TO_INT8_SAT(in.w)) << IM_COL32_A_SHIFT;
1327  return out;
1328 }
1329 
1330 ImU32 ImGui::GetColorU32(ImGuiCol idx, float alpha_mul)
1331 {
1332  ImGuiStyle& style = GImGui->Style;
1333  ImVec4 c = style.Colors[idx];
1334  c.w *= style.Alpha * alpha_mul;
1335  return ColorConvertFloat4ToU32(c);
1336 }
1337 
1339 {
1340  ImGuiStyle& style = GImGui->Style;
1341  ImVec4 c = col;
1342  c.w *= style.Alpha;
1343  return ColorConvertFloat4ToU32(c);
1344 }
1345 
1347 {
1348  ImGuiStyle& style = GImGui->Style;
1349  return style.Colors[idx];
1350 }
1351 
1353 {
1354  float style_alpha = GImGui->Style.Alpha;
1355  if (style_alpha >= 1.0f)
1356  return col;
1357  int a = (col & IM_COL32_A_MASK) >> IM_COL32_A_SHIFT;
1358  a = (int)(a * style_alpha); // We don't need to clamp 0..255 because Style.Alpha is in 0..1 range.
1359  return (col & ~IM_COL32_A_MASK) | (a << IM_COL32_A_SHIFT);
1360 }
1361 
1362 // Convert rgb floats ([0-1],[0-1],[0-1]) to hsv floats ([0-1],[0-1],[0-1]), from Foley & van Dam p592
1363 // Optimized http://lolengine.net/blog/2013/01/13/fast-rgb-to-hsv
1364 void ImGui::ColorConvertRGBtoHSV(float r, float g, float b, float& out_h, float& out_s, float& out_v)
1365 {
1366  float K = 0.f;
1367  if (g < b)
1368  {
1369  ImSwap(g, b);
1370  K = -1.f;
1371  }
1372  if (r < g)
1373  {
1374  ImSwap(r, g);
1375  K = -2.f / 6.f - K;
1376  }
1377 
1378  const float chroma = r - (g < b ? g : b);
1379  out_h = fabsf(K + (g - b) / (6.f * chroma + 1e-20f));
1380  out_s = chroma / (r + 1e-20f);
1381  out_v = r;
1382 }
1383 
1384 // Convert hsv floats ([0-1],[0-1],[0-1]) to rgb floats ([0-1],[0-1],[0-1]), from Foley & van Dam p593
1385 // also http://en.wikipedia.org/wiki/HSL_and_HSV
1386 void ImGui::ColorConvertHSVtoRGB(float h, float s, float v, float& out_r, float& out_g, float& out_b)
1387 {
1388  if (s == 0.0f)
1389  {
1390  // gray
1391  out_r = out_g = out_b = v;
1392  return;
1393  }
1394 
1395  h = fmodf(h, 1.0f) / (60.0f/360.0f);
1396  int i = (int)h;
1397  float f = h - (float)i;
1398  float p = v * (1.0f - s);
1399  float q = v * (1.0f - s * f);
1400  float t = v * (1.0f - s * (1.0f - f));
1401 
1402  switch (i)
1403  {
1404  case 0: out_r = v; out_g = t; out_b = p; break;
1405  case 1: out_r = q; out_g = v; out_b = p; break;
1406  case 2: out_r = p; out_g = v; out_b = t; break;
1407  case 3: out_r = p; out_g = q; out_b = v; break;
1408  case 4: out_r = t; out_g = p; out_b = v; break;
1409  case 5: default: out_r = v; out_g = p; out_b = q; break;
1410  }
1411 }
1412 
1413 FILE* ImFileOpen(const char* filename, const char* mode)
1414 {
1415 #if defined(_WIN32) && !defined(__CYGWIN__)
1416  // We need a fopen() wrapper because MSVC/Windows fopen doesn't handle UTF-8 filenames. Converting both strings from UTF-8 to wchar format (using a single allocation, because we can)
1417  const int filename_wsize = ImTextCountCharsFromUtf8(filename, NULL) + 1;
1418  const int mode_wsize = ImTextCountCharsFromUtf8(mode, NULL) + 1;
1420  buf.resize(filename_wsize + mode_wsize);
1421  ImTextStrFromUtf8(&buf[0], filename_wsize, filename, NULL);
1422  ImTextStrFromUtf8(&buf[filename_wsize], mode_wsize, mode, NULL);
1423  return _wfopen((wchar_t*)&buf[0], (wchar_t*)&buf[filename_wsize]);
1424 #else
1425  return fopen(filename, mode);
1426 #endif
1427 }
1428 
1429 // Load file content into memory
1430 // Memory allocated with ImGui::MemAlloc(), must be freed by user using ImGui::MemFree()
1431 void* ImFileLoadToMemory(const char* filename, const char* file_open_mode, int* out_file_size, int padding_bytes)
1432 {
1433  IM_ASSERT(filename && file_open_mode);
1434  if (out_file_size)
1435  *out_file_size = 0;
1436 
1437  FILE* f;
1438  if ((f = ImFileOpen(filename, file_open_mode)) == NULL)
1439  return NULL;
1440 
1441  long file_size_signed;
1442  if (fseek(f, 0, SEEK_END) || (file_size_signed = ftell(f)) == -1 || fseek(f, 0, SEEK_SET))
1443  {
1444  fclose(f);
1445  return NULL;
1446  }
1447 
1448  int file_size = (int)file_size_signed;
1449  void* file_data = ImGui::MemAlloc(file_size + padding_bytes);
1450  if (file_data == NULL)
1451  {
1452  fclose(f);
1453  return NULL;
1454  }
1455  if (fread(file_data, 1, (size_t)file_size, f) != (size_t)file_size)
1456  {
1457  fclose(f);
1458  ImGui::MemFree(file_data);
1459  return NULL;
1460  }
1461  if (padding_bytes > 0)
1462  memset((void *)(((char*)file_data) + file_size), 0, padding_bytes);
1463 
1464  fclose(f);
1465  if (out_file_size)
1466  *out_file_size = file_size;
1467 
1468  return file_data;
1469 }
1470 
1471 //-----------------------------------------------------------------------------
1472 // ImGuiStorage
1473 // Helper: Key->value storage
1474 //-----------------------------------------------------------------------------
1475 
1476 // std::lower_bound but without the bullshit
1478 {
1481  size_t count = (size_t)(last - first);
1482  while (count > 0)
1483  {
1484  size_t count2 = count >> 1;
1486  if (mid->key < key)
1487  {
1488  first = ++mid;
1489  count -= count2 + 1;
1490  }
1491  else
1492  {
1493  count = count2;
1494  }
1495  }
1496  return first;
1497 }
1498 
1499 // For quicker full rebuild of a storage (instead of an incremental one), you may add all your contents and then sort once.
1501 {
1502  struct StaticFunc
1503  {
1504  static int IMGUI_CDECL PairCompareByID(const void* lhs, const void* rhs)
1505  {
1506  // We can't just do a subtraction because qsort uses signed integers and subtracting our ID doesn't play well with that.
1507  if (((const Pair*)lhs)->key > ((const Pair*)rhs)->key) return +1;
1508  if (((const Pair*)lhs)->key < ((const Pair*)rhs)->key) return -1;
1509  return 0;
1510  }
1511  };
1512  if (Data.Size > 1)
1513  qsort(Data.Data, (size_t)Data.Size, sizeof(Pair), StaticFunc::PairCompareByID);
1514 }
1515 
1516 int ImGuiStorage::GetInt(ImGuiID key, int default_val) const
1517 {
1519  if (it == Data.end() || it->key != key)
1520  return default_val;
1521  return it->val_i;
1522 }
1523 
1524 bool ImGuiStorage::GetBool(ImGuiID key, bool default_val) const
1525 {
1526  return GetInt(key, default_val ? 1 : 0) != 0;
1527 }
1528 
1529 float ImGuiStorage::GetFloat(ImGuiID key, float default_val) const
1530 {
1532  if (it == Data.end() || it->key != key)
1533  return default_val;
1534  return it->val_f;
1535 }
1536 
1538 {
1540  if (it == Data.end() || it->key != key)
1541  return NULL;
1542  return it->val_p;
1543 }
1544 
1545 // References are only valid until a new value is added to the storage. Calling a Set***() function or a Get***Ref() function invalidates the pointer.
1546 int* ImGuiStorage::GetIntRef(ImGuiID key, int default_val)
1547 {
1549  if (it == Data.end() || it->key != key)
1550  it = Data.insert(it, Pair(key, default_val));
1551  return &it->val_i;
1552 }
1553 
1554 bool* ImGuiStorage::GetBoolRef(ImGuiID key, bool default_val)
1555 {
1556  return (bool*)GetIntRef(key, default_val ? 1 : 0);
1557 }
1558 
1559 float* ImGuiStorage::GetFloatRef(ImGuiID key, float default_val)
1560 {
1562  if (it == Data.end() || it->key != key)
1563  it = Data.insert(it, Pair(key, default_val));
1564  return &it->val_f;
1565 }
1566 
1567 void** ImGuiStorage::GetVoidPtrRef(ImGuiID key, void* default_val)
1568 {
1570  if (it == Data.end() || it->key != key)
1571  it = Data.insert(it, Pair(key, default_val));
1572  return &it->val_p;
1573 }
1574 
1575 // FIXME-OPT: Need a way to reuse the result of lower_bound when doing GetInt()/SetInt() - not too bad because it only happens on explicit interaction (maximum one a frame)
1577 {
1579  if (it == Data.end() || it->key != key)
1580  {
1581  Data.insert(it, Pair(key, val));
1582  return;
1583  }
1584  it->val_i = val;
1585 }
1586 
1588 {
1589  SetInt(key, val ? 1 : 0);
1590 }
1591 
1593 {
1595  if (it == Data.end() || it->key != key)
1596  {
1597  Data.insert(it, Pair(key, val));
1598  return;
1599  }
1600  it->val_f = val;
1601 }
1602 
1604 {
1606  if (it == Data.end() || it->key != key)
1607  {
1608  Data.insert(it, Pair(key, val));
1609  return;
1610  }
1611  it->val_p = val;
1612 }
1613 
1615 {
1616  for (int i = 0; i < Data.Size; i++)
1617  Data[i].val_i = v;
1618 }
1619 
1620 //-----------------------------------------------------------------------------
1621 // ImGuiTextFilter
1622 //-----------------------------------------------------------------------------
1623 
1624 // Helper: Parse and apply text filters. In format "aaaaa[,bbbb][,ccccc]"
1625 ImGuiTextFilter::ImGuiTextFilter(const char* default_filter)
1626 {
1627  if (default_filter)
1628  {
1629  ImStrncpy(InputBuf, default_filter, IM_ARRAYSIZE(InputBuf));
1630  Build();
1631  }
1632  else
1633  {
1634  InputBuf[0] = 0;
1635  CountGrep = 0;
1636  }
1637 }
1638 
1639 bool ImGuiTextFilter::Draw(const char* label, float width)
1640 {
1641  if (width != 0.0f)
1643  bool value_changed = ImGui::InputText(label, InputBuf, IM_ARRAYSIZE(InputBuf));
1644  if (width != 0.0f)
1646  if (value_changed)
1647  Build();
1648  return value_changed;
1649 }
1650 
1652 {
1653  out.resize(0);
1654  const char* wb = b;
1655  const char* we = wb;
1656  while (we < e)
1657  {
1658  if (*we == separator)
1659  {
1660  out.push_back(TextRange(wb, we));
1661  wb = we + 1;
1662  }
1663  we++;
1664  }
1665  if (wb != we)
1666  out.push_back(TextRange(wb, we));
1667 }
1668 
1670 {
1671  Filters.resize(0);
1672  TextRange input_range(InputBuf, InputBuf+strlen(InputBuf));
1673  input_range.split(',', Filters);
1674 
1675  CountGrep = 0;
1676  for (int i = 0; i != Filters.Size; i++)
1677  {
1678  Filters[i].trim_blanks();
1679  if (Filters[i].empty())
1680  continue;
1681  if (Filters[i].front() != '-')
1682  CountGrep += 1;
1683  }
1684 }
1685 
1686 bool ImGuiTextFilter::PassFilter(const char* text, const char* text_end) const
1687 {
1688  if (Filters.empty())
1689  return true;
1690 
1691  if (text == NULL)
1692  text = "";
1693 
1694  for (int i = 0; i != Filters.Size; i++)
1695  {
1696  const TextRange& f = Filters[i];
1697  if (f.empty())
1698  continue;
1699  if (f.front() == '-')
1700  {
1701  // Subtract
1702  if (ImStristr(text, text_end, f.begin()+1, f.end()) != NULL)
1703  return false;
1704  }
1705  else
1706  {
1707  // Grep
1708  if (ImStristr(text, text_end, f.begin(), f.end()) != NULL)
1709  return true;
1710  }
1711  }
1712 
1713  // Implicit * grep
1714  if (CountGrep == 0)
1715  return true;
1716 
1717  return false;
1718 }
1719 
1720 //-----------------------------------------------------------------------------
1721 // ImGuiTextBuffer
1722 //-----------------------------------------------------------------------------
1723 
1724 // On some platform vsnprintf() takes va_list by reference and modifies it.
1725 // va_copy is the 'correct' way to copy a va_list but Visual Studio prior to 2013 doesn't have it.
1726 #ifndef va_copy
1727 #define va_copy(dest, src) (dest = src)
1728 #endif
1729 
1730 // Helper: Text buffer for logging/accumulating text
1731 void ImGuiTextBuffer::appendfv(const char* fmt, va_list args)
1732 {
1733  va_list args_copy;
1734  va_copy(args_copy, args);
1735 
1736  int len = ImFormatStringV(NULL, 0, fmt, args); // FIXME-OPT: could do a first pass write attempt, likely successful on first pass.
1737  if (len <= 0)
1738  return;
1739 
1740  const int write_off = Buf.Size;
1741  const int needed_sz = write_off + len;
1742  if (write_off + len >= Buf.Capacity)
1743  {
1744  int double_capacity = Buf.Capacity * 2;
1745  Buf.reserve(needed_sz > double_capacity ? needed_sz : double_capacity);
1746  }
1747 
1748  Buf.resize(needed_sz);
1749  ImFormatStringV(&Buf[write_off - 1], len + 1, fmt, args_copy);
1750 }
1751 
1752 void ImGuiTextBuffer::appendf(const char* fmt, ...)
1753 {
1754  va_list args;
1755  va_start(args, fmt);
1756  appendfv(fmt, args);
1757  va_end(args);
1758 }
1759 
1760 //-----------------------------------------------------------------------------
1761 // ImGuiSimpleColumns (internal use only)
1762 //-----------------------------------------------------------------------------
1763 
1765 {
1766  Count = 0;
1767  Spacing = Width = NextWidth = 0.0f;
1768  memset(Pos, 0, sizeof(Pos));
1769  memset(NextWidths, 0, sizeof(NextWidths));
1770 }
1771 
1772 void ImGuiMenuColumns::Update(int count, float spacing, bool clear)
1773 {
1774  IM_ASSERT(Count <= IM_ARRAYSIZE(Pos));
1775  Count = count;
1776  Width = NextWidth = 0.0f;
1777  Spacing = spacing;
1778  if (clear) memset(NextWidths, 0, sizeof(NextWidths));
1779  for (int i = 0; i < Count; i++)
1780  {
1781  if (i > 0 && NextWidths[i] > 0.0f)
1782  Width += Spacing;
1783  Pos[i] = (float)(int)Width;
1784  Width += NextWidths[i];
1785  NextWidths[i] = 0.0f;
1786  }
1787 }
1788 
1789 float ImGuiMenuColumns::DeclColumns(float w0, float w1, float w2) // not using va_arg because they promote float to double
1790 {
1791  NextWidth = 0.0f;
1792  NextWidths[0] = ImMax(NextWidths[0], w0);
1793  NextWidths[1] = ImMax(NextWidths[1], w1);
1794  NextWidths[2] = ImMax(NextWidths[2], w2);
1795  for (int i = 0; i < 3; i++)
1796  NextWidth += NextWidths[i] + ((i > 0 && NextWidths[i] > 0.0f) ? Spacing : 0.0f);
1797  return ImMax(Width, NextWidth);
1798 }
1799 
1801 {
1802  return ImMax(0.0f, avail_w - Width);
1803 }
1804 
1805 //-----------------------------------------------------------------------------
1806 // ImGuiListClipper
1807 //-----------------------------------------------------------------------------
1808 
1809 static void SetCursorPosYAndSetupDummyPrevLine(float pos_y, float line_height)
1810 {
1811  // Set cursor position and a few other things so that SetScrollHere() and Columns() can work when seeking cursor.
1812  // FIXME: It is problematic that we have to do that here, because custom/equivalent end-user code would stumble on the same issue. Consider moving within SetCursorXXX functions?
1813  ImGui::SetCursorPosY(pos_y);
1815  window->DC.CursorPosPrevLine.y = window->DC.CursorPos.y - line_height; // Setting those fields so that SetScrollHere() can properly function after the end of our clipper usage.
1816  window->DC.PrevLineHeight = (line_height - GImGui->Style.ItemSpacing.y); // If we end up needing more accurate data (to e.g. use SameLine) we may as well make the clipper have a fourth step to let user process and display the last item in their list.
1817  if (window->DC.ColumnsSet)
1818  window->DC.ColumnsSet->CellMinY = window->DC.CursorPos.y; // Setting this so that cell Y position are set properly
1819 }
1820 
1821 // Use case A: Begin() called from constructor with items_height<0, then called again from Sync() in StepNo 1
1822 // Use case B: Begin() called from constructor with items_height>0
1823 // FIXME-LEGACY: Ideally we should remove the Begin/End functions but they are part of the legacy API we still support. This is why some of the code in Step() calling Begin() and reassign some fields, spaghetti style.
1824 void ImGuiListClipper::Begin(int count, float items_height)
1825 {
1826  StartPosY = ImGui::GetCursorPosY();
1827  ItemsHeight = items_height;
1828  ItemsCount = count;
1829  StepNo = 0;
1830  DisplayEnd = DisplayStart = -1;
1831  if (ItemsHeight > 0.0f)
1832  {
1833  ImGui::CalcListClipping(ItemsCount, ItemsHeight, &DisplayStart, &DisplayEnd); // calculate how many to clip/display
1834  if (DisplayStart > 0)
1835  SetCursorPosYAndSetupDummyPrevLine(StartPosY + DisplayStart * ItemsHeight, ItemsHeight); // advance cursor
1836  StepNo = 2;
1837  }
1838 }
1839 
1841 {
1842  if (ItemsCount < 0)
1843  return;
1844  // In theory here we should assert that ImGui::GetCursorPosY() == StartPosY + DisplayEnd * ItemsHeight, but it feels saner to just seek at the end and not assert/crash the user.
1845  if (ItemsCount < INT_MAX)
1846  SetCursorPosYAndSetupDummyPrevLine(StartPosY + ItemsCount * ItemsHeight, ItemsHeight); // advance cursor
1847  ItemsCount = -1;
1848  StepNo = 3;
1849 }
1850 
1852 {
1853  if (ItemsCount == 0 || ImGui::GetCurrentWindowRead()->SkipItems)
1854  {
1855  ItemsCount = -1;
1856  return false;
1857  }
1858  if (StepNo == 0) // Step 0: the clipper let you process the first element, regardless of it being visible or not, so we can measure the element height.
1859  {
1860  DisplayStart = 0;
1861  DisplayEnd = 1;
1862  StartPosY = ImGui::GetCursorPosY();
1863  StepNo = 1;
1864  return true;
1865  }
1866  if (StepNo == 1) // Step 1: the clipper infer height from first element, calculate the actual range of elements to display, and position the cursor before the first element.
1867  {
1868  if (ItemsCount == 1) { ItemsCount = -1; return false; }
1869  float items_height = ImGui::GetCursorPosY() - StartPosY;
1870  IM_ASSERT(items_height > 0.0f); // If this triggers, it means Item 0 hasn't moved the cursor vertically
1871  Begin(ItemsCount-1, items_height);
1872  DisplayStart++;
1873  DisplayEnd++;
1874  StepNo = 3;
1875  return true;
1876  }
1877  if (StepNo == 2) // Step 2: dummy step only required if an explicit items_height was passed to constructor or Begin() and user still call Step(). Does nothing and switch to Step 3.
1878  {
1879  IM_ASSERT(DisplayStart >= 0 && DisplayEnd >= 0);
1880  StepNo = 3;
1881  return true;
1882  }
1883  if (StepNo == 3) // Step 3: the clipper validate that we have reached the expected Y position (corresponding to element DisplayEnd), advance the cursor to the end of the list and then returns 'false' to end the loop.
1884  End();
1885  return false;
1886 }
1887 
1888 //-----------------------------------------------------------------------------
1889 // ImGuiWindow
1890 //-----------------------------------------------------------------------------
1891 
1893 {
1894  Name = ImStrdup(name);
1895  ID = ImHash(name, 0);
1896  IDStack.push_back(ID);
1897  Flags = 0;
1898  PosFloat = Pos = ImVec2(0.0f, 0.0f);
1899  Size = SizeFull = ImVec2(0.0f, 0.0f);
1900  SizeContents = SizeContentsExplicit = ImVec2(0.0f, 0.0f);
1901  WindowPadding = ImVec2(0.0f, 0.0f);
1902  WindowRounding = 0.0f;
1903  WindowBorderSize = 0.0f;
1904  MoveId = GetID("#MOVE");
1905  ChildId = 0;
1906  Scroll = ImVec2(0.0f, 0.0f);
1907  ScrollTarget = ImVec2(FLT_MAX, FLT_MAX);
1908  ScrollTargetCenterRatio = ImVec2(0.5f, 0.5f);
1909  ScrollbarX = ScrollbarY = false;
1910  ScrollbarSizes = ImVec2(0.0f, 0.0f);
1911  Active = WasActive = false;
1912  WriteAccessed = false;
1913  Collapsed = false;
1914  CollapseToggleWanted = false;
1915  SkipItems = false;
1916  Appearing = false;
1917  CloseButton = false;
1918  BeginOrderWithinParent = -1;
1919  BeginOrderWithinContext = -1;
1920  BeginCount = 0;
1921  PopupId = 0;
1922  AutoFitFramesX = AutoFitFramesY = -1;
1923  AutoFitOnlyGrows = false;
1924  AutoFitChildAxises = 0x00;
1925  AutoPosLastDirection = ImGuiDir_None;
1926  HiddenFrames = 0;
1927  SetWindowPosAllowFlags = SetWindowSizeAllowFlags = SetWindowCollapsedAllowFlags = ImGuiCond_Always | ImGuiCond_Once | ImGuiCond_FirstUseEver | ImGuiCond_Appearing;
1928  SetWindowPosVal = SetWindowPosPivot = ImVec2(FLT_MAX, FLT_MAX);
1929 
1930  LastFrameActive = -1;
1931  ItemWidthDefault = 0.0f;
1932  FontWindowScale = 1.0f;
1933 
1934  DrawList = IM_NEW(ImDrawList)(&context->DrawListSharedData);
1935  DrawList->_OwnerName = Name;
1936  ParentWindow = NULL;
1937  RootWindow = NULL;
1938  RootWindowForTitleBarHighlight = NULL;
1939  RootWindowForTabbing = NULL;
1940  RootWindowForNav = NULL;
1941 
1942  NavLastIds[0] = NavLastIds[1] = 0;
1943  NavRectRel[0] = NavRectRel[1] = ImRect();
1944  NavLastChildNavWindow = NULL;
1945 
1946  FocusIdxAllCounter = FocusIdxTabCounter = -1;
1947  FocusIdxAllRequestCurrent = FocusIdxTabRequestCurrent = INT_MAX;
1948  FocusIdxAllRequestNext = FocusIdxTabRequestNext = INT_MAX;
1949 }
1950 
1952 {
1953  IM_DELETE(DrawList);
1954  IM_DELETE(Name);
1955  for (int i = 0; i != ColumnsStorage.Size; i++)
1956  ColumnsStorage[i].~ImGuiColumnsSet();
1957 }
1958 
1959 ImGuiID ImGuiWindow::GetID(const char* str, const char* str_end)
1960 {
1961  ImGuiID seed = IDStack.back();
1962  ImGuiID id = ImHash(str, str_end ? (int)(str_end - str) : 0, seed);
1963  ImGui::KeepAliveID(id);
1964  return id;
1965 }
1966 
1967 ImGuiID ImGuiWindow::GetID(const void* ptr)
1968 {
1969  ImGuiID seed = IDStack.back();
1970  ImGuiID id = ImHash(&ptr, sizeof(void*), seed);
1971  ImGui::KeepAliveID(id);
1972  return id;
1973 }
1974 
1975 ImGuiID ImGuiWindow::GetIDNoKeepAlive(const char* str, const char* str_end)
1976 {
1977  ImGuiID seed = IDStack.back();
1978  return ImHash(str, str_end ? (int)(str_end - str) : 0, seed);
1979 }
1980 
1981 // This is only used in rare/specific situations to manufacture an ID out of nowhere.
1983 {
1984  ImGuiID seed = IDStack.back();
1985  const int r_rel[4] = { (int)(r_abs.Min.x - Pos.x), (int)(r_abs.Min.y - Pos.y), (int)(r_abs.Max.x - Pos.x), (int)(r_abs.Max.y - Pos.y) };
1986  ImGuiID id = ImHash(&r_rel, sizeof(r_rel), seed);
1987  ImGui::KeepAliveID(id);
1988  return id;
1989 }
1990 
1991 //-----------------------------------------------------------------------------
1992 // Internal API exposed in imgui_internal.h
1993 //-----------------------------------------------------------------------------
1994 
1995 static void SetCurrentWindow(ImGuiWindow* window)
1996 {
1997  ImGuiContext& g = *GImGui;
1998  g.CurrentWindow = window;
1999  if (window)
2000  g.FontSize = g.DrawListSharedData.FontSize = window->CalcFontSize();
2001 }
2002 
2003 static void SetNavID(ImGuiID id, int nav_layer)
2004 {
2005  ImGuiContext& g = *GImGui;
2006  IM_ASSERT(g.NavWindow);
2007  IM_ASSERT(nav_layer == 0 || nav_layer == 1);
2008  g.NavId = id;
2009  g.NavWindow->NavLastIds[nav_layer] = id;
2010 }
2011 
2012 static void SetNavIDAndMoveMouse(ImGuiID id, int nav_layer, const ImRect& rect_rel)
2013 {
2014  ImGuiContext& g = *GImGui;
2015  SetNavID(id, nav_layer);
2016  g.NavWindow->NavRectRel[nav_layer] = rect_rel;
2017  g.NavMousePosDirty = true;
2018  g.NavDisableHighlight = false;
2019  g.NavDisableMouseHover = true;
2020 }
2021 
2023 {
2024  ImGuiContext& g = *GImGui;
2025  g.ActiveIdIsJustActivated = (g.ActiveId != id);
2026  if (g.ActiveIdIsJustActivated)
2027  g.ActiveIdTimer = 0.0f;
2028  g.ActiveId = id;
2029  g.ActiveIdAllowNavDirFlags = 0;
2030  g.ActiveIdAllowOverlap = false;
2031  g.ActiveIdWindow = window;
2032  if (id)
2033  {
2034  g.ActiveIdIsAlive = true;
2035  g.ActiveIdSource = (g.NavActivateId == id || g.NavInputId == id || g.NavJustTabbedId == id || g.NavJustMovedToId == id) ? ImGuiInputSource_Nav : ImGuiInputSource_Mouse;
2036  }
2037 }
2038 
2040 {
2041  ImGuiContext& g = *GImGui;
2042  return g.ActiveId;
2043 }
2044 
2046 {
2047  ImGuiContext& g = *GImGui;
2048  IM_ASSERT(id != 0);
2049 
2050  // Assume that SetFocusID() is called in the context where its NavLayer is the current layer, which is the case everywhere we call it.
2051  const int nav_layer = window->DC.NavLayerCurrent;
2052  if (g.NavWindow != window)
2053  g.NavInitRequest = false;
2054  g.NavId = id;
2055  g.NavWindow = window;
2056  g.NavLayer = nav_layer;
2057  window->NavLastIds[nav_layer] = id;
2058  if (window->DC.LastItemId == id)
2059  window->NavRectRel[nav_layer] = ImRect(window->DC.LastItemRect.Min - window->Pos, window->DC.LastItemRect.Max - window->Pos);
2060 
2061  if (g.ActiveIdSource == ImGuiInputSource_Nav)
2062  g.NavDisableMouseHover = true;
2063  else
2064  g.NavDisableHighlight = true;
2065 }
2066 
2068 {
2069  SetActiveID(0, NULL);
2070 }
2071 
2073 {
2074  ImGuiContext& g = *GImGui;
2075  g.HoveredId = id;
2076  g.HoveredIdAllowOverlap = false;
2077  g.HoveredIdTimer = (id != 0 && g.HoveredIdPreviousFrame == id) ? (g.HoveredIdTimer + g.IO.DeltaTime) : 0.0f;
2078 }
2079 
2081 {
2082  ImGuiContext& g = *GImGui;
2083  return g.HoveredId ? g.HoveredId : g.HoveredIdPreviousFrame;
2084 }
2085 
2087 {
2088  ImGuiContext& g = *GImGui;
2089  if (g.ActiveId == id)
2090  g.ActiveIdIsAlive = true;
2091 }
2092 
2094 {
2095  // An active popup disable hovering on other windows (apart from its own children)
2096  // FIXME-OPT: This could be cached/stored within the window.
2097  ImGuiContext& g = *GImGui;
2098  if (g.NavWindow)
2099  if (ImGuiWindow* focused_root_window = g.NavWindow->RootWindow)
2100  if (focused_root_window->WasActive && focused_root_window != window->RootWindow)
2101  {
2102  // For the purpose of those flags we differentiate "standard popup" from "modal popup"
2103  // NB: The order of those two tests is important because Modal windows are also Popups.
2104  if (focused_root_window->Flags & ImGuiWindowFlags_Modal)
2105  return false;
2106  if ((focused_root_window->Flags & ImGuiWindowFlags_Popup) && !(flags & ImGuiHoveredFlags_AllowWhenBlockedByPopup))
2107  return false;
2108  }
2109 
2110  return true;
2111 }
2112 
2113 // Advance cursor given item size for layout.
2114 void ImGui::ItemSize(const ImVec2& size, float text_offset_y)
2115 {
2116  ImGuiContext& g = *GImGui;
2117  ImGuiWindow* window = g.CurrentWindow;
2118  if (window->SkipItems)
2119  return;
2120 
2121  // Always align ourselves on pixel boundaries
2122  const float line_height = ImMax(window->DC.CurrentLineHeight, size.y);
2123  const float text_base_offset = ImMax(window->DC.CurrentLineTextBaseOffset, text_offset_y);
2124  //if (g.IO.KeyAlt) window->DrawList->AddRect(window->DC.CursorPos, window->DC.CursorPos + ImVec2(size.x, line_height), IM_COL32(255,0,0,200)); // [DEBUG]
2125  window->DC.CursorPosPrevLine = ImVec2(window->DC.CursorPos.x + size.x, window->DC.CursorPos.y);
2126  window->DC.CursorPos = ImVec2((float)(int)(window->Pos.x + window->DC.IndentX + window->DC.ColumnsOffsetX), (float)(int)(window->DC.CursorPos.y + line_height + g.Style.ItemSpacing.y));
2127  window->DC.CursorMaxPos.x = ImMax(window->DC.CursorMaxPos.x, window->DC.CursorPosPrevLine.x);
2128  window->DC.CursorMaxPos.y = ImMax(window->DC.CursorMaxPos.y, window->DC.CursorPos.y - g.Style.ItemSpacing.y);
2129  //if (g.IO.KeyAlt) window->DrawList->AddCircle(window->DC.CursorMaxPos, 3.0f, IM_COL32(255,0,0,255), 4); // [DEBUG]
2130 
2131  window->DC.PrevLineHeight = line_height;
2132  window->DC.PrevLineTextBaseOffset = text_base_offset;
2133  window->DC.CurrentLineHeight = window->DC.CurrentLineTextBaseOffset = 0.0f;
2134 
2135  // Horizontal layout mode
2136  if (window->DC.LayoutType == ImGuiLayoutType_Horizontal)
2137  SameLine();
2138 }
2139 
2140 void ImGui::ItemSize(const ImRect& bb, float text_offset_y)
2141 {
2142  ItemSize(bb.GetSize(), text_offset_y);
2143 }
2144 
2145 static ImGuiDir NavScoreItemGetQuadrant(float dx, float dy)
2146 {
2147  if (fabsf(dx) > fabsf(dy))
2148  return (dx > 0.0f) ? ImGuiDir_Right : ImGuiDir_Left;
2149  return (dy > 0.0f) ? ImGuiDir_Down : ImGuiDir_Up;
2150 }
2151 
2152 static float NavScoreItemDistInterval(float a0, float a1, float b0, float b1)
2153 {
2154  if (a1 < b0)
2155  return a1 - b0;
2156  if (b1 < a0)
2157  return a0 - b1;
2158  return 0.0f;
2159 }
2160 
2161 // Scoring function for directional navigation. Based on https://gist.github.com/rygorous/6981057
2163 {
2164  ImGuiContext& g = *GImGui;
2165  ImGuiWindow* window = g.CurrentWindow;
2166  if (g.NavLayer != window->DC.NavLayerCurrent)
2167  return false;
2168 
2169  const ImRect& curr = g.NavScoringRectScreen; // Current modified source rect (NB: we've applied Max.x = Min.x in NavUpdate() to inhibit the effect of having varied item width)
2170  g.NavScoringCount++;
2171 
2172  // We perform scoring on items bounding box clipped by their parent window on the other axis (clipping on our movement axis would give us equal scores for all clipped items)
2173  if (g.NavMoveDir == ImGuiDir_Left || g.NavMoveDir == ImGuiDir_Right)
2174  {
2175  cand.Min.y = ImClamp(cand.Min.y, window->ClipRect.Min.y, window->ClipRect.Max.y);
2176  cand.Max.y = ImClamp(cand.Max.y, window->ClipRect.Min.y, window->ClipRect.Max.y);
2177  }
2178  else
2179  {
2180  cand.Min.x = ImClamp(cand.Min.x, window->ClipRect.Min.x, window->ClipRect.Max.x);
2181  cand.Max.x = ImClamp(cand.Max.x, window->ClipRect.Min.x, window->ClipRect.Max.x);
2182  }
2183 
2184  // Compute distance between boxes
2185  // FIXME-NAV: Introducing biases for vertical navigation, needs to be removed.
2186  float dbx = NavScoreItemDistInterval(cand.Min.x, cand.Max.x, curr.Min.x, curr.Max.x);
2187  float dby = NavScoreItemDistInterval(ImLerp(cand.Min.y, cand.Max.y, 0.2f), ImLerp(cand.Min.y, cand.Max.y, 0.8f), ImLerp(curr.Min.y, curr.Max.y, 0.2f), ImLerp(curr.Min.y, curr.Max.y, 0.8f)); // Scale down on Y to keep using box-distance for vertically touching items
2188  if (dby != 0.0f && dbx != 0.0f)
2189  dbx = (dbx/1000.0f) + ((dbx > 0.0f) ? +1.0f : -1.0f);
2190  float dist_box = fabsf(dbx) + fabsf(dby);
2191 
2192  // Compute distance between centers (this is off by a factor of 2, but we only compare center distances with each other so it doesn't matter)
2193  float dcx = (cand.Min.x + cand.Max.x) - (curr.Min.x + curr.Max.x);
2194  float dcy = (cand.Min.y + cand.Max.y) - (curr.Min.y + curr.Max.y);
2195  float dist_center = fabsf(dcx) + fabsf(dcy); // L1 metric (need this for our connectedness guarantee)
2196 
2197  // Determine which quadrant of 'curr' our candidate item 'cand' lies in based on distance
2198  ImGuiDir quadrant;
2199  float dax = 0.0f, day = 0.0f, dist_axial = 0.0f;
2200  if (dbx != 0.0f || dby != 0.0f)
2201  {
2202  // For non-overlapping boxes, use distance between boxes
2203  dax = dbx;
2204  day = dby;
2205  dist_axial = dist_box;
2206  quadrant = NavScoreItemGetQuadrant(dbx, dby);
2207  }
2208  else if (dcx != 0.0f || dcy != 0.0f)
2209  {
2210  // For overlapping boxes with different centers, use distance between centers
2211  dax = dcx;
2212  day = dcy;
2213  dist_axial = dist_center;
2214  quadrant = NavScoreItemGetQuadrant(dcx, dcy);
2215  }
2216  else
2217  {
2218  // Degenerate case: two overlapping buttons with same center, break ties arbitrarily (note that LastItemId here is really the _previous_ item order, but it doesn't matter)
2219  quadrant = (window->DC.LastItemId < g.NavId) ? ImGuiDir_Left : ImGuiDir_Right;
2220  }
2221 
2222 #if IMGUI_DEBUG_NAV_SCORING
2223  char buf[128];
2224  if (ImGui::IsMouseHoveringRect(cand.Min, cand.Max))
2225  {
2226  ImFormatString(buf, IM_ARRAYSIZE(buf), "dbox (%.2f,%.2f->%.4f)\ndcen (%.2f,%.2f->%.4f)\nd (%.2f,%.2f->%.4f)\nnav %c, quadrant %c", dbx, dby, dist_box, dcx, dcy, dist_center, dax, day, dist_axial, "WENS"[g.NavMoveDir], "WENS"[quadrant]);
2227  g.OverlayDrawList.AddRect(curr.Min, curr.Max, IM_COL32(255, 200, 0, 100));
2228  g.OverlayDrawList.AddRect(cand.Min, cand.Max, IM_COL32(255,255,0,200));
2229  g.OverlayDrawList.AddRectFilled(cand.Max-ImVec2(4,4), cand.Max+ImGui::CalcTextSize(buf)+ImVec2(4,4), IM_COL32(40,0,0,150));
2230  g.OverlayDrawList.AddText(g.IO.FontDefault, 13.0f, cand.Max, ~0U, buf);
2231  }
2232  else if (g.IO.KeyCtrl) // Hold to preview score in matching quadrant. Press C to rotate.
2233  {
2234  if (IsKeyPressedMap(ImGuiKey_C)) { g.NavMoveDirLast = (ImGuiDir)((g.NavMoveDirLast + 1) & 3); g.IO.KeysDownDuration[g.IO.KeyMap[ImGuiKey_C]] = 0.01f; }
2235  if (quadrant == g.NavMoveDir)
2236  {
2237  ImFormatString(buf, IM_ARRAYSIZE(buf), "%.0f/%.0f", dist_box, dist_center);
2238  g.OverlayDrawList.AddRectFilled(cand.Min, cand.Max, IM_COL32(255, 0, 0, 200));
2239  g.OverlayDrawList.AddText(g.IO.FontDefault, 13.0f, cand.Min, IM_COL32(255, 255, 255, 255), buf);
2240  }
2241  }
2242  #endif
2243 
2244  // Is it in the quadrant we're interesting in moving to?
2245  bool new_best = false;
2246  if (quadrant == g.NavMoveDir)
2247  {
2248  // Does it beat the current best candidate?
2249  if (dist_box < result->DistBox)
2250  {
2251  result->DistBox = dist_box;
2252  result->DistCenter = dist_center;
2253  return true;
2254  }
2255  if (dist_box == result->DistBox)
2256  {
2257  // Try using distance between center points to break ties
2258  if (dist_center < result->DistCenter)
2259  {
2260  result->DistCenter = dist_center;
2261  new_best = true;
2262  }
2263  else if (dist_center == result->DistCenter)
2264  {
2265  // Still tied! we need to be extra-careful to make sure everything gets linked properly. We consistently break ties by symbolically moving "later" items
2266  // (with higher index) to the right/downwards by an infinitesimal amount since we the current "best" button already (so it must have a lower index),
2267  // this is fairly easy. This rule ensures that all buttons with dx==dy==0 will end up being linked in order of appearance along the x axis.
2268  if (((g.NavMoveDir == ImGuiDir_Up || g.NavMoveDir == ImGuiDir_Down) ? dby : dbx) < 0.0f) // moving bj to the right/down decreases distance
2269  new_best = true;
2270  }
2271  }
2272  }
2273 
2274  // Axial check: if 'curr' has no link at all in some direction and 'cand' lies roughly in that direction, add a tentative link. This will only be kept if no "real" matches
2275  // are found, so it only augments the graph produced by the above method using extra links. (important, since it doesn't guarantee strong connectedness)
2276  // This is just to avoid buttons having no links in a particular direction when there's a suitable neighbor. you get good graphs without this too.
2277  // 2017/09/29: FIXME: This now currently only enabled inside menu bars, ideally we'd disable it everywhere. Menus in particular need to catch failure. For general navigation it feels awkward.
2278  // Disabling it may however lead to disconnected graphs when nodes are very spaced out on different axis. Perhaps consider offering this as an option?
2279  if (result->DistBox == FLT_MAX && dist_axial < result->DistAxial) // Check axial match
2280  if (g.NavLayer == 1 && !(g.NavWindow->Flags & ImGuiWindowFlags_ChildMenu))
2281  if ((g.NavMoveDir == ImGuiDir_Left && dax < 0.0f) || (g.NavMoveDir == ImGuiDir_Right && dax > 0.0f) || (g.NavMoveDir == ImGuiDir_Up && day < 0.0f) || (g.NavMoveDir == ImGuiDir_Down && day > 0.0f))
2282  {
2283  result->DistAxial = dist_axial;
2284  new_best = true;
2285  }
2286 
2287  return new_best;
2288 }
2289 
2290 static void NavSaveLastChildNavWindow(ImGuiWindow* child_window)
2291 {
2292  ImGuiWindow* parent_window = child_window;
2293  while (parent_window && (parent_window->Flags & ImGuiWindowFlags_ChildWindow) != 0 && (parent_window->Flags & (ImGuiWindowFlags_Popup | ImGuiWindowFlags_ChildMenu)) == 0)
2294  parent_window = parent_window->ParentWindow;
2295  if (parent_window && parent_window != child_window)
2296  parent_window->NavLastChildNavWindow = child_window;
2297 }
2298 
2299 // Call when we are expected to land on Layer 0 after FocusWindow()
2301 {
2302  return window->NavLastChildNavWindow ? window->NavLastChildNavWindow : window;
2303 }
2304 
2305 static void NavRestoreLayer(int layer)
2306 {
2307  ImGuiContext& g = *GImGui;
2308  g.NavLayer = layer;
2309  if (layer == 0)
2310  g.NavWindow = NavRestoreLastChildNavWindow(g.NavWindow);
2311  if (layer == 0 && g.NavWindow->NavLastIds[0] != 0)
2312  SetNavIDAndMoveMouse(g.NavWindow->NavLastIds[0], layer, g.NavWindow->NavRectRel[0]);
2313  else
2314  ImGui::NavInitWindow(g.NavWindow, true);
2315 }
2316 
2317 static inline void NavUpdateAnyRequestFlag()
2318 {
2319  ImGuiContext& g = *GImGui;
2320  g.NavAnyRequest = g.NavMoveRequest || g.NavInitRequest || IMGUI_DEBUG_NAV_SCORING;
2321 }
2322 
2324 {
2325  ImGuiContext& g = *GImGui;
2326  return g.NavMoveRequest && g.NavMoveResultLocal.ID == 0 && g.NavMoveResultOther.ID == 0;
2327 }
2328 
2330 {
2331  ImGuiContext& g = *GImGui;
2332  g.NavMoveRequest = false;
2334 }
2335 
2336 // We get there when either NavId == id, or when g.NavAnyRequest is set (which is updated by NavUpdateAnyRequestFlag above)
2337 static void ImGui::NavProcessItem(ImGuiWindow* window, const ImRect& nav_bb, const ImGuiID id)
2338 {
2339  ImGuiContext& g = *GImGui;
2340  //if (!g.IO.NavActive) // [2017/10/06] Removed this possibly redundant test but I am not sure of all the side-effects yet. Some of the feature here will need to work regardless of using a _NoNavInputs flag.
2341  // return;
2342 
2343  const ImGuiItemFlags item_flags = window->DC.ItemFlags;
2344  const ImRect nav_bb_rel(nav_bb.Min - window->Pos, nav_bb.Max - window->Pos);
2345  if (g.NavInitRequest && g.NavLayer == window->DC.NavLayerCurrent)
2346  {
2347  // Even if 'ImGuiItemFlags_NoNavDefaultFocus' is on (typically collapse/close button) we record the first ResultId so they can be used as a fallback
2348  if (!(item_flags & ImGuiItemFlags_NoNavDefaultFocus) || g.NavInitResultId == 0)
2349  {
2350  g.NavInitResultId = id;
2351  g.NavInitResultRectRel = nav_bb_rel;
2352  }
2353  if (!(item_flags & ImGuiItemFlags_NoNavDefaultFocus))
2354  {
2355  g.NavInitRequest = false; // Found a match, clear request
2357  }
2358  }
2359 
2360  // Scoring for navigation
2361  if (g.NavId != id && !(item_flags & ImGuiItemFlags_NoNav))
2362  {
2363  ImGuiNavMoveResult* result = (window == g.NavWindow) ? &g.NavMoveResultLocal : &g.NavMoveResultOther;
2365  // [DEBUG] Score all items in NavWindow at all times
2366  if (!g.NavMoveRequest)
2367  g.NavMoveDir = g.NavMoveDirLast;
2368  bool new_best = NavScoreItem(result, nav_bb) && g.NavMoveRequest;
2369 #else
2370  bool new_best = g.NavMoveRequest && NavScoreItem(result, nav_bb);
2371 #endif
2372  if (new_best)
2373  {
2374  result->ID = id;
2375  result->ParentID = window->IDStack.back();
2376  result->Window = window;
2377  result->RectRel = nav_bb_rel;
2378  }
2379  }
2380 
2381  // Update window-relative bounding box of navigated item
2382  if (g.NavId == id)
2383  {
2384  g.NavWindow = window; // Always refresh g.NavWindow, because some operations such as FocusItem() don't have a window.
2385  g.NavLayer = window->DC.NavLayerCurrent;
2386  g.NavIdIsAlive = true;
2387  g.NavIdTabCounter = window->FocusIdxTabCounter;
2388  window->NavRectRel[window->DC.NavLayerCurrent] = nav_bb_rel; // Store item bounding box (relative to window position)
2389  }
2390 }
2391 
2392 // Declare item bounding box for clipping and interaction.
2393 // Note that the size can be different than the one provided to ItemSize(). Typically, widgets that spread over available surface
2394 // declare their minimum size requirement to ItemSize() and then use a larger region for drawing/interaction, which is passed to ItemAdd().
2395 bool ImGui::ItemAdd(const ImRect& bb, ImGuiID id, const ImRect* nav_bb_arg)
2396 {
2397  ImGuiContext& g = *GImGui;
2398  ImGuiWindow* window = g.CurrentWindow;
2399 
2400  if (id != 0)
2401  {
2402  // Navigation processing runs prior to clipping early-out
2403  // (a) So that NavInitRequest can be honored, for newly opened windows to select a default widget
2404  // (b) So that we can scroll up/down past clipped items. This adds a small O(N) cost to regular navigation requests unfortunately, but it is still limited to one window.
2405  // it may not scale very well for windows with ten of thousands of item, but at least NavMoveRequest is only set on user interaction, aka maximum once a frame.
2406  // We could early out with "if (is_clipped && !g.NavInitRequest) return false;" but when we wouldn't be able to reach unclipped widgets. This would work if user had explicit scrolling control (e.g. mapped on a stick)
2407  window->DC.NavLayerActiveMaskNext |= window->DC.NavLayerCurrentMask;
2408  if (g.NavId == id || g.NavAnyRequest)
2409  if (g.NavWindow->RootWindowForNav == window->RootWindowForNav)
2410  if (window == g.NavWindow || ((window->Flags | g.NavWindow->Flags) & ImGuiWindowFlags_NavFlattened))
2411  NavProcessItem(window, nav_bb_arg ? *nav_bb_arg : bb, id);
2412  }
2413 
2414  window->DC.LastItemId = id;
2415  window->DC.LastItemRect = bb;
2416  window->DC.LastItemStatusFlags = 0;
2417 
2418  // Clipping test
2419  const bool is_clipped = IsClippedEx(bb, id, false);
2420  if (is_clipped)
2421  return false;
2422  //if (g.IO.KeyAlt) window->DrawList->AddRect(bb.Min, bb.Max, IM_COL32(255,255,0,120)); // [DEBUG]
2423 
2424  // We need to calculate this now to take account of the current clipping rectangle (as items like Selectable may change them)
2425  if (IsMouseHoveringRect(bb.Min, bb.Max))
2427  return true;
2428 }
2429 
2430 // This is roughly matching the behavior of internal-facing ItemHoverable()
2431 // - we allow hovering to be true when ActiveId==window->MoveID, so that clicking on non-interactive items such as a Text() item still returns true with IsItemHovered()
2432 // - this should work even for non-interactive items that have no ID, so we cannot use LastItemId
2434 {
2435  ImGuiContext& g = *GImGui;
2436  ImGuiWindow* window = g.CurrentWindow;
2437  if (g.NavDisableMouseHover && !g.NavDisableHighlight)
2438  return IsItemFocused();
2439 
2440  // Test for bounding box overlap, as updated as ItemAdd()
2442  return false;
2443  IM_ASSERT((flags & (ImGuiHoveredFlags_RootWindow | ImGuiHoveredFlags_ChildWindows)) == 0); // Flags not supported by this function
2444 
2445  // Test if we are hovering the right window (our window could be behind another window)
2446  // [2017/10/16] Reverted commit 344d48be3 and testing RootWindow instead. I believe it is correct to NOT test for RootWindow but this leaves us unable to use IsItemHovered() after EndChild() itself.
2447  // Until a solution is found I believe reverting to the test from 2017/09/27 is safe since this was the test that has been running for a long while.
2448  //if (g.HoveredWindow != window)
2449  // return false;
2450  if (g.HoveredRootWindow != window->RootWindow && !(flags & ImGuiHoveredFlags_AllowWhenOverlapped))
2451  return false;
2452 
2453  // Test if another item is active (e.g. being dragged)
2455  if (g.ActiveId != 0 && g.ActiveId != window->DC.LastItemId && !g.ActiveIdAllowOverlap && g.ActiveId != window->MoveId)
2456  return false;
2457 
2458  // Test if interactions on this window are blocked by an active popup or modal
2459  if (!IsWindowContentHoverable(window, flags))
2460  return false;
2461 
2462  // Test if the item is disabled
2463  if (window->DC.ItemFlags & ImGuiItemFlags_Disabled)
2464  return false;
2465 
2466  // Special handling for the 1st item after Begin() which represent the title bar. When the window is collapsed (SkipItems==true) that last item will never be overwritten so we need to detect tht case.
2467  if (window->DC.LastItemId == window->MoveId && window->WriteAccessed)
2468  return false;
2469  return true;
2470 }
2471 
2472 // Internal facing ItemHoverable() used when submitting widgets. Differs slightly from IsItemHovered().
2474 {
2475  ImGuiContext& g = *GImGui;
2476  if (g.HoveredId != 0 && g.HoveredId != id && !g.HoveredIdAllowOverlap)
2477  return false;
2478 
2479  ImGuiWindow* window = g.CurrentWindow;
2480  if (g.HoveredWindow != window)
2481  return false;
2482  if (g.ActiveId != 0 && g.ActiveId != id && !g.ActiveIdAllowOverlap)
2483  return false;
2484  if (!IsMouseHoveringRect(bb.Min, bb.Max))
2485  return false;
2486  if (g.NavDisableMouseHover || !IsWindowContentHoverable(window, ImGuiHoveredFlags_Default))
2487  return false;
2488  if (window->DC.ItemFlags & ImGuiItemFlags_Disabled)
2489  return false;
2490 
2491  SetHoveredID(id);
2492  return true;
2493 }
2494 
2495 bool ImGui::IsClippedEx(const ImRect& bb, ImGuiID id, bool clip_even_when_logged)
2496 {
2497  ImGuiContext& g = *GImGui;
2498  ImGuiWindow* window = g.CurrentWindow;
2499  if (!bb.Overlaps(window->ClipRect))
2500  if (id == 0 || id != g.ActiveId)
2501  if (clip_even_when_logged || !g.LogEnabled)
2502  return true;
2503  return false;
2504 }
2505 
2506 bool ImGui::FocusableItemRegister(ImGuiWindow* window, ImGuiID id, bool tab_stop)
2507 {
2508  ImGuiContext& g = *GImGui;
2509 
2511  window->FocusIdxAllCounter++;
2512  if (allow_keyboard_focus)
2513  window->FocusIdxTabCounter++;
2514 
2515  // Process keyboard input at this point: TAB/Shift-TAB to tab out of the currently focused item.
2516  // Note that we can always TAB out of a widget that doesn't allow tabbing in.
2517  if (tab_stop && (g.ActiveId == id) && window->FocusIdxAllRequestNext == INT_MAX && window->FocusIdxTabRequestNext == INT_MAX && !g.IO.KeyCtrl && IsKeyPressedMap(ImGuiKey_Tab))
2518  window->FocusIdxTabRequestNext = window->FocusIdxTabCounter + (g.IO.KeyShift ? (allow_keyboard_focus ? -1 : 0) : +1); // Modulo on index will be applied at the end of frame once we've got the total counter of items.
2519 
2520  if (window->FocusIdxAllCounter == window->FocusIdxAllRequestCurrent)
2521  return true;
2522  if (allow_keyboard_focus && window->FocusIdxTabCounter == window->FocusIdxTabRequestCurrent)
2523  {
2524  g.NavJustTabbedId = id;
2525  return true;
2526  }
2527 
2528  return false;
2529 }
2530 
2532 {
2533  window->FocusIdxAllCounter--;
2534  window->FocusIdxTabCounter--;
2535 }
2536 
2537 ImVec2 ImGui::CalcItemSize(ImVec2 size, float default_x, float default_y)
2538 {
2539  ImGuiContext& g = *GImGui;
2540  ImVec2 content_max;
2541  if (size.x < 0.0f || size.y < 0.0f)
2542  content_max = g.CurrentWindow->Pos + GetContentRegionMax();
2543  if (size.x <= 0.0f)
2544  size.x = (size.x == 0.0f) ? default_x : ImMax(content_max.x - g.CurrentWindow->DC.CursorPos.x, 4.0f) + size.x;
2545  if (size.y <= 0.0f)
2546  size.y = (size.y == 0.0f) ? default_y : ImMax(content_max.y - g.CurrentWindow->DC.CursorPos.y, 4.0f) + size.y;
2547  return size;
2548 }
2549 
2550 float ImGui::CalcWrapWidthForPos(const ImVec2& pos, float wrap_pos_x)
2551 {
2552  if (wrap_pos_x < 0.0f)
2553  return 0.0f;
2554 
2555  ImGuiWindow* window = GetCurrentWindowRead();
2556  if (wrap_pos_x == 0.0f)
2557  wrap_pos_x = GetContentRegionMax().x + window->Pos.x;
2558  else if (wrap_pos_x > 0.0f)
2559  wrap_pos_x += window->Pos.x - window->Scroll.x; // wrap_pos_x is provided is window local space
2560 
2561  return ImMax(wrap_pos_x - pos.x, 1.0f);
2562 }
2563 
2564 //-----------------------------------------------------------------------------
2565 
2566 void* ImGui::MemAlloc(size_t sz)
2567 {
2570 }
2571 
2572 void ImGui::MemFree(void* ptr)
2573 {
2576 }
2577 
2579 {
2581 }
2582 
2583 void ImGui::SetClipboardText(const char* text)
2584 {
2587 }
2588 
2589 const char* ImGui::GetVersion()
2590 {
2591  return IMGUI_VERSION;
2592 }
2593 
2594 // Internal state access - if you want to share ImGui state between modules (e.g. DLL) or allocate it yourself
2595 // Note that we still point to some static data and members (such as GFontAtlas), so the state instance you end up using will point to the static data within its module
2597 {
2598  return GImGui;
2599 }
2600 
2602 {
2603 #ifdef IMGUI_SET_CURRENT_CONTEXT_FUNC
2604  IMGUI_SET_CURRENT_CONTEXT_FUNC(ctx); // For custom thread-based hackery you may want to have control over this.
2605 #else
2606  GImGui = ctx;
2607 #endif
2608 }
2609 
2610 void ImGui::SetAllocatorFunctions(void* (*alloc_func)(size_t sz, void* user_data), void(*free_func)(void* ptr, void* user_data), void* user_data)
2611 {
2612  GImAllocatorAllocFunc = alloc_func;
2613  GImAllocatorFreeFunc = free_func;
2614  GImAllocatorUserData = user_data;
2615 }
2616 
2618 {
2619  ImGuiContext* ctx = IM_NEW(ImGuiContext)(shared_font_atlas);
2620  if (GImGui == NULL)
2621  SetCurrentContext(ctx);
2622  Initialize(ctx);
2623  return ctx;
2624 }
2625 
2627 {
2628  if (ctx == NULL)
2629  ctx = GImGui;
2630  Shutdown(ctx);
2631  if (GImGui == ctx)
2633  IM_DELETE(ctx);
2634 }
2635 
2637 {
2638  IM_ASSERT(GImGui != NULL && "No current context. Did you call ImGui::CreateContext() or ImGui::SetCurrentContext()?");
2639  return GImGui->IO;
2640 }
2641 
2643 {
2644  IM_ASSERT(GImGui != NULL && "No current context. Did you call ImGui::CreateContext() or ImGui::SetCurrentContext()?");
2645  return GImGui->Style;
2646 }
2647 
2648 // Same value as passed to the old io.RenderDrawListsFn function. Valid after Render() and until the next call to NewFrame()
2650 {
2651  ImGuiContext& g = *GImGui;
2652  return g.DrawData.Valid ? &g.DrawData : NULL;
2653 }
2654 
2656 {
2657  return GImGui->Time;
2658 }
2659 
2661 {
2662  return GImGui->FrameCount;
2663 }
2664 
2666 {
2667  return &GImGui->OverlayDrawList;
2668 }
2669 
2671 {
2672  return &GImGui->DrawListSharedData;
2673 }
2674 
2675 // This needs to be called before we submit any widget (aka in or before Begin)
2676 void ImGui::NavInitWindow(ImGuiWindow* window, bool force_reinit)
2677 {
2678  ImGuiContext& g = *GImGui;
2679  IM_ASSERT(window == g.NavWindow);
2680  bool init_for_nav = false;
2681  if (!(window->Flags & ImGuiWindowFlags_NoNavInputs))
2682  if (!(window->Flags & ImGuiWindowFlags_ChildWindow) || (window->Flags & ImGuiWindowFlags_Popup) || (window->NavLastIds[0] == 0) || force_reinit)
2683  init_for_nav = true;
2684  if (init_for_nav)
2685  {
2686  SetNavID(0, g.NavLayer);
2687  g.NavInitRequest = true;
2688  g.NavInitRequestFromMove = false;
2689  g.NavInitResultId = 0;
2690  g.NavInitResultRectRel = ImRect();
2692  }
2693  else
2694  {
2695  g.NavId = window->NavLastIds[0];
2696  }
2697 }
2698 
2700 {
2701  ImGuiContext& g = *GImGui;
2702  ImGuiWindow* window = g.NavWindow;
2703  if (!window)
2704  return g.IO.MousePos;
2705  const ImRect& rect_rel = window->NavRectRel[g.NavLayer];
2706  ImVec2 pos = g.NavWindow->Pos + ImVec2(rect_rel.Min.x + ImMin(g.Style.FramePadding.x*4, rect_rel.GetWidth()), rect_rel.Max.y - ImMin(g.Style.FramePadding.y, rect_rel.GetHeight()));
2707  ImRect visible_rect = GetViewportRect();
2708  return ImFloor(ImClamp(pos, visible_rect.Min, visible_rect.Max)); // ImFloor() is important because non-integer mouse position application in back-end might be lossy and result in undesirable non-zero delta.
2709 }
2710 
2711 static int FindWindowIndex(ImGuiWindow* window) // FIXME-OPT O(N)
2712 {
2713  ImGuiContext& g = *GImGui;
2714  for (int i = g.Windows.Size-1; i >= 0; i--)
2715  if (g.Windows[i] == window)
2716  return i;
2717  return -1;
2718 }
2719 
2720 static ImGuiWindow* FindWindowNavigable(int i_start, int i_stop, int dir) // FIXME-OPT O(N)
2721 {
2722  ImGuiContext& g = *GImGui;
2723  for (int i = i_start; i >= 0 && i < g.Windows.Size && i != i_stop; i += dir)
2724  if (ImGui::IsWindowNavFocusable(g.Windows[i]))
2725  return g.Windows[i];
2726  return NULL;
2727 }
2728 
2730 {
2731  ImGuiContext& g = *GImGui;
2733  return g.IO.NavInputs[n]; // Instant, read analog input (0.0f..1.0f, as provided by user)
2734 
2735  const float t = g.IO.NavInputsDownDuration[n];
2736  if (t < 0.0f && mode == ImGuiInputReadMode_Released) // Return 1.0f when just released, no repeat, ignore analog input.
2737  return (g.IO.NavInputsDownDurationPrev[n] >= 0.0f ? 1.0f : 0.0f);
2738  if (t < 0.0f)
2739  return 0.0f;
2740  if (mode == ImGuiInputReadMode_Pressed) // Return 1.0f when just pressed, no repeat, ignore analog input.
2741  return (t == 0.0f) ? 1.0f : 0.0f;
2743  return (float)CalcTypematicPressedRepeatAmount(t, t - g.IO.DeltaTime, g.IO.KeyRepeatDelay * 0.80f, g.IO.KeyRepeatRate * 0.80f);
2745  return (float)CalcTypematicPressedRepeatAmount(t, t - g.IO.DeltaTime, g.IO.KeyRepeatDelay * 1.00f, g.IO.KeyRepeatRate * 2.00f);
2747  return (float)CalcTypematicPressedRepeatAmount(t, t - g.IO.DeltaTime, g.IO.KeyRepeatDelay * 0.80f, g.IO.KeyRepeatRate * 0.30f);
2748  return 0.0f;
2749 }
2750 
2751 // Equivalent of IsKeyDown() for NavInputs[]
2753 {
2754  return GImGui->IO.NavInputs[n] > 0.0f;
2755 }
2756 
2757 // Equivalent of IsKeyPressed() for NavInputs[]
2759 {
2760  return ImGui::GetNavInputAmount(n, mode) > 0.0f;
2761 }
2762 
2764 {
2765  return (ImGui::GetNavInputAmount(n1, mode) + ImGui::GetNavInputAmount(n2, mode)) > 0.0f;
2766 }
2767 
2768 ImVec2 ImGui::GetNavInputAmount2d(ImGuiNavDirSourceFlags dir_sources, ImGuiInputReadMode mode, float slow_factor, float fast_factor)
2769 {
2770  ImVec2 delta(0.0f, 0.0f);
2771  if (dir_sources & ImGuiNavDirSourceFlags_Keyboard)
2773  if (dir_sources & ImGuiNavDirSourceFlags_PadDPad)
2775  if (dir_sources & ImGuiNavDirSourceFlags_PadLStick)
2777  if (slow_factor != 0.0f && IsNavInputDown(ImGuiNavInput_TweakSlow))
2778  delta *= slow_factor;
2779  if (fast_factor != 0.0f && IsNavInputDown(ImGuiNavInput_TweakFast))
2780  delta *= fast_factor;
2781  return delta;
2782 }
2783 
2784 static void NavUpdateWindowingHighlightWindow(int focus_change_dir)
2785 {
2786  ImGuiContext& g = *GImGui;
2787  IM_ASSERT(g.NavWindowingTarget);
2788  if (g.NavWindowingTarget->Flags & ImGuiWindowFlags_Modal)
2789  return;
2790 
2791  const int i_current = FindWindowIndex(g.NavWindowingTarget);
2792  ImGuiWindow* window_target = FindWindowNavigable(i_current + focus_change_dir, -INT_MAX, focus_change_dir);
2793  if (!window_target)
2794  window_target = FindWindowNavigable((focus_change_dir < 0) ? (g.Windows.Size - 1) : 0, i_current, focus_change_dir);
2795  g.NavWindowingTarget = window_target;
2796  g.NavWindowingToggleLayer = false;
2797 }
2798 
2799 // Window management mode (hold to: change focus/move/resize, tap to: toggle menu layer)
2801 {
2802  ImGuiContext& g = *GImGui;
2803  ImGuiWindow* apply_focus_window = NULL;
2804  bool apply_toggle_layer = false;
2805 
2806  bool start_windowing_with_gamepad = !g.NavWindowingTarget && IsNavInputPressed(ImGuiNavInput_Menu, ImGuiInputReadMode_Pressed);
2807  bool start_windowing_with_keyboard = !g.NavWindowingTarget && g.IO.KeyCtrl && IsKeyPressedMap(ImGuiKey_Tab) && (g.IO.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard);
2808  if (start_windowing_with_gamepad || start_windowing_with_keyboard)
2809  if (ImGuiWindow* window = g.NavWindow ? g.NavWindow : FindWindowNavigable(g.Windows.Size - 1, -INT_MAX, -1))
2810  {
2811  g.NavWindowingTarget = window->RootWindowForTabbing;
2812  g.NavWindowingHighlightTimer = g.NavWindowingHighlightAlpha = 0.0f;
2813  g.NavWindowingToggleLayer = start_windowing_with_keyboard ? false : true;
2814  g.NavWindowingInputSource = start_windowing_with_keyboard ? ImGuiInputSource_NavKeyboard : ImGuiInputSource_NavGamepad;
2815  }
2816 
2817  // Gamepad update
2818  g.NavWindowingHighlightTimer += g.IO.DeltaTime;
2819  if (g.NavWindowingTarget && g.NavWindowingInputSource == ImGuiInputSource_NavGamepad)
2820  {
2821  // Highlight only appears after a brief time holding the button, so that a fast tap on PadMenu (to toggle NavLayer) doesn't add visual noise
2822  g.NavWindowingHighlightAlpha = ImMax(g.NavWindowingHighlightAlpha, ImSaturate((g.NavWindowingHighlightTimer - 0.20f) / 0.05f));
2823 
2824  // Select window to focus
2826  if (focus_change_dir != 0)
2827  {
2828  NavUpdateWindowingHighlightWindow(focus_change_dir);
2829  g.NavWindowingHighlightAlpha = 1.0f;
2830  }
2831 
2832  // Single press toggles NavLayer, long press with L/R apply actual focus on release (until then the window was merely rendered front-most)
2834  {
2835  g.NavWindowingToggleLayer &= (g.NavWindowingHighlightAlpha < 1.0f); // Once button was held long enough we don't consider it a tap-to-toggle-layer press anymore.
2836  if (g.NavWindowingToggleLayer && g.NavWindow)
2837  apply_toggle_layer = true;
2838  else if (!g.NavWindowingToggleLayer)
2839  apply_focus_window = g.NavWindowingTarget;
2840  g.NavWindowingTarget = NULL;
2841  }
2842  }
2843 
2844  // Keyboard: Focus
2845  if (g.NavWindowingTarget && g.NavWindowingInputSource == ImGuiInputSource_NavKeyboard)
2846  {
2847  // Visuals only appears after a brief time after pressing TAB the first time, so that a fast CTRL+TAB doesn't add visual noise
2848  g.NavWindowingHighlightAlpha = ImMax(g.NavWindowingHighlightAlpha, ImSaturate((g.NavWindowingHighlightTimer - 0.15f) / 0.04f)); // 1.0f
2849  if (IsKeyPressedMap(ImGuiKey_Tab, true))
2850  NavUpdateWindowingHighlightWindow(g.IO.KeyShift ? +1 : -1);
2851  if (!g.IO.KeyCtrl)
2852  apply_focus_window = g.NavWindowingTarget;
2853  }
2854 
2855  // Keyboard: Press and Release ALT to toggle menu layer
2856  // FIXME: We lack an explicit IO variable for "is the imgui window focused", so compare mouse validity to detect the common case of back-end clearing releases all keys on ALT-TAB
2857  if ((g.ActiveId == 0 || g.ActiveIdAllowOverlap) && IsNavInputPressed(ImGuiNavInput_KeyMenu_, ImGuiInputReadMode_Released))
2858  if (IsMousePosValid(&g.IO.MousePos) == IsMousePosValid(&g.IO.MousePosPrev))
2859  apply_toggle_layer = true;
2860 
2861  // Move window
2862  if (g.NavWindowingTarget && !(g.NavWindowingTarget->Flags & ImGuiWindowFlags_NoMove))
2863  {
2864  ImVec2 move_delta;
2865  if (g.NavWindowingInputSource == ImGuiInputSource_NavKeyboard && !g.IO.KeyShift)
2867  if (g.NavWindowingInputSource == ImGuiInputSource_NavGamepad)
2869  if (move_delta.x != 0.0f || move_delta.y != 0.0f)
2870  {
2871  const float NAV_MOVE_SPEED = 800.0f;
2872  const float move_speed = ImFloor(NAV_MOVE_SPEED * g.IO.DeltaTime * ImMin(g.IO.DisplayFramebufferScale.x, g.IO.DisplayFramebufferScale.y));
2873  g.NavWindowingTarget->PosFloat += move_delta * move_speed;
2874  g.NavDisableMouseHover = true;
2875  MarkIniSettingsDirty(g.NavWindowingTarget);
2876  }
2877  }
2878 
2879  // Apply final focus
2880  if (apply_focus_window && (g.NavWindow == NULL || apply_focus_window != g.NavWindow->RootWindowForTabbing))
2881  {
2882  g.NavDisableHighlight = false;
2883  g.NavDisableMouseHover = true;
2884  apply_focus_window = NavRestoreLastChildNavWindow(apply_focus_window);
2885  ClosePopupsOverWindow(apply_focus_window);
2886  FocusWindow(apply_focus_window);
2887  if (apply_focus_window->NavLastIds[0] == 0)
2888  NavInitWindow(apply_focus_window, false);
2889 
2890  // If the window only has a menu layer, select it directly
2891  if (apply_focus_window->DC.NavLayerActiveMask == (1 << 1))
2892  g.NavLayer = 1;
2893  }
2894  if (apply_focus_window)
2895  g.NavWindowingTarget = NULL;
2896 
2897  // Apply menu/layer toggle
2898  if (apply_toggle_layer && g.NavWindow)
2899  {
2900  ImGuiWindow* new_nav_window = g.NavWindow;
2901  while ((new_nav_window->DC.NavLayerActiveMask & (1 << 1)) == 0 && (new_nav_window->Flags & ImGuiWindowFlags_ChildWindow) != 0 && (new_nav_window->Flags & (ImGuiWindowFlags_Popup | ImGuiWindowFlags_ChildMenu)) == 0)
2902  new_nav_window = new_nav_window->ParentWindow;
2903  if (new_nav_window != g.NavWindow)
2904  {
2905  ImGuiWindow* old_nav_window = g.NavWindow;
2906  FocusWindow(new_nav_window);
2907  new_nav_window->NavLastChildNavWindow = old_nav_window;
2908  }
2909  g.NavDisableHighlight = false;
2910  g.NavDisableMouseHover = true;
2911  NavRestoreLayer((g.NavWindow->DC.NavLayerActiveMask & (1 << 1)) ? (g.NavLayer ^ 1) : 0);
2912  }
2913 }
2914 
2915 // NB: We modify rect_rel by the amount we scrolled for, so it is immediately updated.
2916 static void NavScrollToBringItemIntoView(ImGuiWindow* window, ImRect& item_rect_rel)
2917 {
2918  // Scroll to keep newly navigated item fully into view
2919  ImRect window_rect_rel(window->InnerRect.Min - window->Pos - ImVec2(1, 1), window->InnerRect.Max - window->Pos + ImVec2(1, 1));
2920  //g.OverlayDrawList.AddRect(window->Pos + window_rect_rel.Min, window->Pos + window_rect_rel.Max, IM_COL32_WHITE); // [DEBUG]
2921  if (window_rect_rel.Contains(item_rect_rel))
2922  return;
2923 
2924  ImGuiContext& g = *GImGui;
2925  if (window->ScrollbarX && item_rect_rel.Min.x < window_rect_rel.Min.x)
2926  {
2927  window->ScrollTarget.x = item_rect_rel.Min.x + window->Scroll.x - g.Style.ItemSpacing.x;
2928  window->ScrollTargetCenterRatio.x = 0.0f;
2929  }
2930  else if (window->ScrollbarX && item_rect_rel.Max.x >= window_rect_rel.Max.x)
2931  {
2932  window->ScrollTarget.x = item_rect_rel.Max.x + window->Scroll.x + g.Style.ItemSpacing.x;
2933  window->ScrollTargetCenterRatio.x = 1.0f;
2934  }
2935  if (item_rect_rel.Min.y < window_rect_rel.Min.y)
2936  {
2937  window->ScrollTarget.y = item_rect_rel.Min.y + window->Scroll.y - g.Style.ItemSpacing.y;
2938  window->ScrollTargetCenterRatio.y = 0.0f;
2939  }
2940  else if (item_rect_rel.Max.y >= window_rect_rel.Max.y)
2941  {
2942  window->ScrollTarget.y = item_rect_rel.Max.y + window->Scroll.y + g.Style.ItemSpacing.y;
2943  window->ScrollTargetCenterRatio.y = 1.0f;
2944  }
2945 
2946  // Estimate upcoming scroll so we can offset our relative mouse position so mouse position can be applied immediately (under this block)
2947  ImVec2 next_scroll = CalcNextScrollFromScrollTargetAndClamp(window);
2948  item_rect_rel.Translate(window->Scroll - next_scroll);
2949 }
2950 
2951 static void ImGui::NavUpdate()
2952 {
2953  ImGuiContext& g = *GImGui;
2954  g.IO.WantMoveMouse = false;
2955 
2956 #if 0
2957  if (g.NavScoringCount > 0) printf("[%05d] NavScoringCount %d for '%s' layer %d (Init:%d, Move:%d)\n", g.FrameCount, g.NavScoringCount, g.NavWindow ? g.NavWindow->Name : "NULL", g.NavLayer, g.NavInitRequest || g.NavInitResultId != 0, g.NavMoveRequest);
2958 #endif
2959 
2960  // Update Keyboard->Nav inputs mapping
2961  memset(g.IO.NavInputs + ImGuiNavInput_InternalStart_, 0, (ImGuiNavInput_COUNT - ImGuiNavInput_InternalStart_) * sizeof(g.IO.NavInputs[0]));
2962  if (g.IO.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard)
2963  {
2964  #define NAV_MAP_KEY(_KEY, _NAV_INPUT) if (g.IO.KeyMap[_KEY] != -1 && IsKeyDown(g.IO.KeyMap[_KEY])) g.IO.NavInputs[_NAV_INPUT] = 1.0f;
2972  if (g.IO.KeyCtrl) g.IO.NavInputs[ImGuiNavInput_TweakSlow] = 1.0f;
2973  if (g.IO.KeyShift) g.IO.NavInputs[ImGuiNavInput_TweakFast] = 1.0f;
2974  if (g.IO.KeyAlt) g.IO.NavInputs[ImGuiNavInput_KeyMenu_] = 1.0f;
2975 #undef NAV_MAP_KEY
2976  }
2977 
2978  memcpy(g.IO.NavInputsDownDurationPrev, g.IO.NavInputsDownDuration, sizeof(g.IO.NavInputsDownDuration));
2979  for (int i = 0; i < IM_ARRAYSIZE(g.IO.NavInputs); i++)
2980  g.IO.NavInputsDownDuration[i] = (g.IO.NavInputs[i] > 0.0f) ? (g.IO.NavInputsDownDuration[i] < 0.0f ? 0.0f : g.IO.NavInputsDownDuration[i] + g.IO.DeltaTime) : -1.0f;
2981 
2982  // Process navigation init request (select first/default focus)
2983  if (g.NavInitResultId != 0 && (!g.NavDisableHighlight || g.NavInitRequestFromMove))
2984  {
2985  // Apply result from previous navigation init request (will typically select the first item, unless SetItemDefaultFocus() has been called)
2986  IM_ASSERT(g.NavWindow);
2987  if (g.NavInitRequestFromMove)
2988  SetNavIDAndMoveMouse(g.NavInitResultId, g.NavLayer, g.NavInitResultRectRel);
2989  else
2990  SetNavID(g.NavInitResultId, g.NavLayer);
2991  g.NavWindow->NavRectRel[g.NavLayer] = g.NavInitResultRectRel;
2992  }
2993  g.NavInitRequest = false;
2994  g.NavInitRequestFromMove = false;
2995  g.NavInitResultId = 0;
2996  g.NavJustMovedToId = 0;
2997 
2998  // Process navigation move request
2999  if (g.NavMoveRequest && (g.NavMoveResultLocal.ID != 0 || g.NavMoveResultOther.ID != 0))
3000  {
3001  // Select which result to use
3002  ImGuiNavMoveResult* result = (g.NavMoveResultLocal.ID != 0) ? &g.NavMoveResultLocal : &g.NavMoveResultOther;
3003  if (g.NavMoveResultOther.ID != 0 && g.NavMoveResultOther.Window->ParentWindow == g.NavWindow) // Maybe entering a flattened child? In this case solve the tie using the regular scoring rules
3004  if ((g.NavMoveResultOther.DistBox < g.NavMoveResultLocal.DistBox) || (g.NavMoveResultOther.DistBox == g.NavMoveResultLocal.DistBox && g.NavMoveResultOther.DistCenter < g.NavMoveResultLocal.DistCenter))
3005  result = &g.NavMoveResultOther;
3006 
3007  IM_ASSERT(g.NavWindow && result->Window);
3008 
3009  // Scroll to keep newly navigated item fully into view
3010  if (g.NavLayer == 0)
3011  NavScrollToBringItemIntoView(result->Window, result->RectRel);
3012 
3013  // Apply result from previous frame navigation directional move request
3014  ClearActiveID();
3015  g.NavWindow = result->Window;
3016  SetNavIDAndMoveMouse(result->ID, g.NavLayer, result->RectRel);
3017  g.NavJustMovedToId = result->ID;
3018  g.NavMoveFromClampedRefRect = false;
3019  }
3020 
3021  // When a forwarded move request failed, we restore the highlight that we disabled during the forward frame
3022  if (g.NavMoveRequestForward == ImGuiNavForward_ForwardActive)
3023  {
3024  IM_ASSERT(g.NavMoveRequest);
3025  if (g.NavMoveResultLocal.ID == 0 && g.NavMoveResultOther.ID == 0)
3026  g.NavDisableHighlight = false;
3027  g.NavMoveRequestForward = ImGuiNavForward_None;
3028  }
3029 
3030  // Apply application mouse position movement, after we had a chance to process move request result.
3031  if (g.NavMousePosDirty && g.NavIdIsAlive)
3032  {
3033  // Set mouse position given our knowledge of the nav widget position from last frame
3034  if (g.IO.ConfigFlags & ImGuiConfigFlags_NavMoveMouse)
3035  {
3036  g.IO.MousePos = g.IO.MousePosPrev = NavCalcPreferredMousePos();
3037  g.IO.WantMoveMouse = true;
3038  }
3039  g.NavMousePosDirty = false;
3040  }
3041  g.NavIdIsAlive = false;
3042  g.NavJustTabbedId = 0;
3043  IM_ASSERT(g.NavLayer == 0 || g.NavLayer == 1);
3044 
3045  // Store our return window (for returning from Layer 1 to Layer 0) and clear it as soon as we step back in our own Layer 0
3046  if (g.NavWindow)
3047  NavSaveLastChildNavWindow(g.NavWindow);
3048  if (g.NavWindow && g.NavWindow->NavLastChildNavWindow != NULL && g.NavLayer == 0)
3049  g.NavWindow->NavLastChildNavWindow = NULL;
3050 
3052 
3053  // Set output flags for user application
3054  g.IO.NavActive = (g.IO.ConfigFlags & (ImGuiConfigFlags_NavEnableGamepad | ImGuiConfigFlags_NavEnableKeyboard)) && g.NavWindow && !(g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs);
3055  g.IO.NavVisible = (g.IO.NavActive && g.NavId != 0 && !g.NavDisableHighlight) || (g.NavWindowingTarget != NULL) || g.NavInitRequest;
3056 
3057  // Process NavCancel input (to close a popup, get back to parent, clear focus)
3059  {
3060  if (g.ActiveId != 0)
3061  {
3062  ClearActiveID();
3063  }
3064  else if (g.NavWindow && (g.NavWindow->Flags & ImGuiWindowFlags_ChildWindow) && !(g.NavWindow->Flags & ImGuiWindowFlags_Popup) && g.NavWindow->ParentWindow)
3065  {
3066  // Exit child window
3067  ImGuiWindow* child_window = g.NavWindow;
3068  ImGuiWindow* parent_window = g.NavWindow->ParentWindow;
3069  IM_ASSERT(child_window->ChildId != 0);
3070  FocusWindow(parent_window);
3071  SetNavID(child_window->ChildId, 0);
3072  g.NavIdIsAlive = false;
3073  if (g.NavDisableMouseHover)
3074  g.NavMousePosDirty = true;
3075  }
3076  else if (g.OpenPopupStack.Size > 0)
3077  {
3078  // Close open popup/menu
3079  if (!(g.OpenPopupStack.back().Window->Flags & ImGuiWindowFlags_Modal))
3080  ClosePopupToLevel(g.OpenPopupStack.Size - 1);
3081  }
3082  else if (g.NavLayer != 0)
3083  {
3084  // Leave the "menu" layer
3085  NavRestoreLayer(0);
3086  }
3087  else
3088  {
3089  // Clear NavLastId for popups but keep it for regular child window so we can leave one and come back where we were
3090  if (g.NavWindow && ((g.NavWindow->Flags & ImGuiWindowFlags_Popup) || !(g.NavWindow->Flags & ImGuiWindowFlags_ChildWindow)))
3091  g.NavWindow->NavLastIds[0] = 0;
3092  g.NavId = 0;
3093  }
3094  }
3095 
3096  // Process manual activation request
3097  g.NavActivateId = g.NavActivateDownId = g.NavActivatePressedId = g.NavInputId = 0;
3098  if (g.NavId != 0 && !g.NavDisableHighlight && !g.NavWindowingTarget && g.NavWindow && !(g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs))
3099  {
3100  bool activate_down = IsNavInputDown(ImGuiNavInput_Activate);
3101  bool activate_pressed = activate_down && IsNavInputPressed(ImGuiNavInput_Activate, ImGuiInputReadMode_Pressed);
3102  if (g.ActiveId == 0 && activate_pressed)
3103  g.NavActivateId = g.NavId;
3104  if ((g.ActiveId == 0 || g.ActiveId == g.NavId) && activate_down)
3105  g.NavActivateDownId = g.NavId;
3106  if ((g.ActiveId == 0 || g.ActiveId == g.NavId) && activate_pressed)
3107  g.NavActivatePressedId = g.NavId;
3108  if ((g.ActiveId == 0 || g.ActiveId == g.NavId) && IsNavInputPressed(ImGuiNavInput_Input, ImGuiInputReadMode_Pressed))
3109  g.NavInputId = g.NavId;
3110  }
3111  if (g.NavWindow && (g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs))
3112  g.NavDisableHighlight = true;
3113  if (g.NavActivateId != 0)
3114  IM_ASSERT(g.NavActivateDownId == g.NavActivateId);
3115  g.NavMoveRequest = false;
3116 
3117  // Process programmatic activation request
3118  if (g.NavNextActivateId != 0)
3119  g.NavActivateId = g.NavActivateDownId = g.NavActivatePressedId = g.NavInputId = g.NavNextActivateId;
3120  g.NavNextActivateId = 0;
3121 
3122  // Initiate directional inputs request
3123  const int allowed_dir_flags = (g.ActiveId == 0) ? ~0 : g.ActiveIdAllowNavDirFlags;
3124  if (g.NavMoveRequestForward == ImGuiNavForward_None)
3125  {
3126  g.NavMoveDir = ImGuiDir_None;
3127  if (g.NavWindow && !g.NavWindowingTarget && allowed_dir_flags && !(g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs))
3128  {
3133  }
3134  }
3135  else
3136  {
3137  // Forwarding previous request (which has been modified, e.g. wrap around menus rewrite the requests with a starting rectangle at the other side of the window)
3138  IM_ASSERT(g.NavMoveDir != ImGuiDir_None);
3139  IM_ASSERT(g.NavMoveRequestForward == ImGuiNavForward_ForwardQueued);
3140  g.NavMoveRequestForward = ImGuiNavForward_ForwardActive;
3141  }
3142 
3143  if (g.NavMoveDir != ImGuiDir_None)
3144  {
3145  g.NavMoveRequest = true;
3146  g.NavMoveDirLast = g.NavMoveDir;
3147  }
3148 
3149  // If we initiate a movement request and have no current NavId, we initiate a InitDefautRequest that will be used as a fallback if the direction fails to find a match
3150  if (g.NavMoveRequest && g.NavId == 0)
3151  {
3152  g.NavInitRequest = g.NavInitRequestFromMove = true;
3153  g.NavInitResultId = 0;
3154  g.NavDisableHighlight = false;
3155  }
3156 
3158 
3159  // Scrolling
3160  if (g.NavWindow && !(g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs) && !g.NavWindowingTarget)
3161  {
3162  // *Fallback* manual-scroll with NavUp/NavDown when window has no navigable item
3163  ImGuiWindow* window = g.NavWindow;
3164  const float scroll_speed = ImFloor(window->CalcFontSize() * 100 * g.IO.DeltaTime + 0.5f); // We need round the scrolling speed because sub-pixel scroll isn't reliably supported.
3165  if (window->DC.NavLayerActiveMask == 0x00 && window->DC.NavHasScroll && g.NavMoveRequest)
3166  {
3167  if (g.NavMoveDir == ImGuiDir_Left || g.NavMoveDir == ImGuiDir_Right)
3168  SetWindowScrollX(window, ImFloor(window->Scroll.x + ((g.NavMoveDir == ImGuiDir_Left) ? -1.0f : +1.0f) * scroll_speed));
3169  if (g.NavMoveDir == ImGuiDir_Up || g.NavMoveDir == ImGuiDir_Down)
3170  SetWindowScrollY(window, ImFloor(window->Scroll.y + ((g.NavMoveDir == ImGuiDir_Up) ? -1.0f : +1.0f) * scroll_speed));
3171  }
3172 
3173  // *Normal* Manual scroll with NavScrollXXX keys
3174  // Next movement request will clamp the NavId reference rectangle to the visible area, so navigation will resume within those bounds.
3176  if (scroll_dir.x != 0.0f && window->ScrollbarX)
3177  {
3178  SetWindowScrollX(window, ImFloor(window->Scroll.x + scroll_dir.x * scroll_speed));
3179  g.NavMoveFromClampedRefRect = true;
3180  }
3181  if (scroll_dir.y != 0.0f)
3182  {
3183  SetWindowScrollY(window, ImFloor(window->Scroll.y + scroll_dir.y * scroll_speed));
3184  g.NavMoveFromClampedRefRect = true;
3185  }
3186  }
3187 
3188  // Reset search results
3189  g.NavMoveResultLocal.Clear();
3190  g.NavMoveResultOther.Clear();
3191 
3192  // When we have manually scrolled (without using navigation) and NavId becomes out of bounds, we project its bounding box to the visible area to restart navigation within visible items
3193  if (g.NavMoveRequest && g.NavMoveFromClampedRefRect && g.NavLayer == 0)
3194  {
3195  ImGuiWindow* window = g.NavWindow;
3196  ImRect window_rect_rel(window->InnerRect.Min - window->Pos - ImVec2(1,1), window->InnerRect.Max - window->Pos + ImVec2(1,1));
3197  if (!window_rect_rel.Contains(window->NavRectRel[g.NavLayer]))
3198  {
3199  float pad = window->CalcFontSize() * 0.5f;
3200  window_rect_rel.Expand(ImVec2(-ImMin(window_rect_rel.GetWidth(), pad), -ImMin(window_rect_rel.GetHeight(), pad))); // Terrible approximation for the intent of starting navigation from first fully visible item
3201  window->NavRectRel[g.NavLayer].ClipWith(window_rect_rel);
3202  g.NavId = 0;
3203  }
3204  g.NavMoveFromClampedRefRect = false;
3205  }
3206 
3207  // For scoring we use a single segment on the left side our current item bounding box (not touching the edge to avoid box overlap with zero-spaced items)
3208  ImRect nav_rect_rel = (g.NavWindow && !g.NavWindow->NavRectRel[g.NavLayer].IsInverted()) ? g.NavWindow->NavRectRel[g.NavLayer] : ImRect(0,0,0,0);
3209  g.NavScoringRectScreen = g.NavWindow ? ImRect(g.NavWindow->Pos + nav_rect_rel.Min, g.NavWindow->Pos + nav_rect_rel.Max) : GetViewportRect();
3210  g.NavScoringRectScreen.Min.x = ImMin(g.NavScoringRectScreen.Min.x + 1.0f, g.NavScoringRectScreen.Max.x);
3211  g.NavScoringRectScreen.Max.x = g.NavScoringRectScreen.Min.x;
3212  IM_ASSERT(!g.NavScoringRectScreen.IsInverted()); // Ensure if we have a finite, non-inverted bounding box here will allows us to remove extraneous fabsf() calls in NavScoreItem().
3213  //g.OverlayDrawList.AddRect(g.NavScoringRectScreen.Min, g.NavScoringRectScreen.Max, IM_COL32(255,200,0,255)); // [DEBUG]
3214  g.NavScoringCount = 0;
3215 #if IMGUI_DEBUG_NAV_RECTS
3216  if (g.NavWindow) { for (int layer = 0; layer < 2; layer++) g.OverlayDrawList.AddRect(g.NavWindow->Pos + g.NavWindow->NavRectRel[layer].Min, g.NavWindow->Pos + g.NavWindow->NavRectRel[layer].Max, IM_COL32(255,200,0,255)); } // [DEBUG]
3217  if (g.NavWindow) { ImU32 col = (g.NavWindow->HiddenFrames <= 0) ? IM_COL32(255,0,255,255) : IM_COL32(255,0,0,255); ImVec2 p = NavCalcPreferredMousePos(); char buf[32]; ImFormatString(buf, 32, "%d", g.NavLayer); g.OverlayDrawList.AddCircleFilled(p, 3.0f, col); g.OverlayDrawList.AddText(NULL, 13.0f, p + ImVec2(8,-4), col, buf); }
3218 #endif
3219 }
3220 
3222 {
3223  ImGuiContext& g = *GImGui;
3224  if (g.MovingWindow && g.MovingWindow->MoveId == g.ActiveId && g.ActiveIdSource == ImGuiInputSource_Mouse)
3225  {
3226  // We actually want to move the root window. g.MovingWindow == window we clicked on (could be a child window).
3227  // We track it to preserve Focus and so that ActiveIdWindow == MovingWindow and ActiveId == MovingWindow->MoveId for consistency.
3228  KeepAliveID(g.ActiveId);
3229  IM_ASSERT(g.MovingWindow && g.MovingWindow->RootWindow);
3230  ImGuiWindow* moving_window = g.MovingWindow->RootWindow;
3231  if (g.IO.MouseDown[0])
3232  {
3233  ImVec2 pos = g.IO.MousePos - g.ActiveIdClickOffset;
3234  if (moving_window->PosFloat.x != pos.x || moving_window->PosFloat.y != pos.y)
3235  {
3236  MarkIniSettingsDirty(moving_window);
3237  moving_window->PosFloat = pos;
3238  }
3239  FocusWindow(g.MovingWindow);
3240  }
3241  else
3242  {
3243  ClearActiveID();
3244  g.MovingWindow = NULL;
3245  }
3246  }
3247  else
3248  {
3249  // When clicking/dragging from a window that has the _NoMove flag, we still set the ActiveId in order to prevent hovering others.
3250  if (g.ActiveIdWindow && g.ActiveIdWindow->MoveId == g.ActiveId)
3251  {
3252  KeepAliveID(g.ActiveId);
3253  if (!g.IO.MouseDown[0])
3254  ClearActiveID();
3255  }
3256  g.MovingWindow = NULL;
3257  }
3258 }
3259 
3261 {
3262  IM_ASSERT(GImGui != NULL && "No current context. Did you call ImGui::CreateContext() or ImGui::SetCurrentContext()?");
3263  ImGuiContext& g = *GImGui;
3264 
3265  // Check user data
3266  // (We pass an error message in the assert expression as a trick to get it visible to programmers who are not using a debugger, as most assert handlers display their argument)
3267  IM_ASSERT(g.Initialized);
3268  IM_ASSERT(g.IO.DeltaTime >= 0.0f && "Need a positive DeltaTime (zero is tolerated but will cause some timing issues)");
3269  IM_ASSERT(g.IO.DisplaySize.x >= 0.0f && g.IO.DisplaySize.y >= 0.0f && "Invalid DisplaySize value");
3270  IM_ASSERT(g.IO.Fonts->Fonts.Size > 0 && "Font Atlas not built. Did you call io.Fonts->GetTexDataAsRGBA32() / GetTexDataAsAlpha8() ?");
3271  IM_ASSERT(g.IO.Fonts->Fonts[0]->IsLoaded() && "Font Atlas not built. Did you call io.Fonts->GetTexDataAsRGBA32() / GetTexDataAsAlpha8() ?");
3272  IM_ASSERT(g.Style.CurveTessellationTol > 0.0f && "Invalid style setting");
3273  IM_ASSERT(g.Style.Alpha >= 0.0f && g.Style.Alpha <= 1.0f && "Invalid style setting. Alpha cannot be negative (allows us to avoid a few clamps in color computations)");
3274  IM_ASSERT((g.FrameCount == 0 || g.FrameCountEnded == g.FrameCount) && "Forgot to call Render() or EndFrame() at the end of the previous frame?");
3275  for (int n = 0; n < ImGuiKey_COUNT; n++)
3276  IM_ASSERT(g.IO.KeyMap[n] >= -1 && g.IO.KeyMap[n] < IM_ARRAYSIZE(g.IO.KeysDown) && "io.KeyMap[] contains an out of bound value (need to be 0..512, or -1 for unmapped key)");
3277 
3278  // Do a simple check for required key mapping (we intentionally do NOT check all keys to not pressure user into setting up everything, but Space is required and was super recently added in 1.60 WIP)
3279  if (g.IO.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard)
3280  IM_ASSERT(g.IO.KeyMap[ImGuiKey_Space] != -1 && "ImGuiKey_Space is not mapped, required for keyboard navigation.");
3281 
3282  // Load settings on first frame
3283  if (!g.SettingsLoaded)
3284  {
3285  IM_ASSERT(g.SettingsWindows.empty());
3286  LoadIniSettingsFromDisk(g.IO.IniFilename);
3287  g.SettingsLoaded = true;
3288  }
3289 
3290  g.Time += g.IO.DeltaTime;
3291  g.FrameCount += 1;
3292  g.TooltipOverrideCount = 0;
3293  g.WindowsActiveCount = 0;
3294 
3296  IM_ASSERT(g.Font->IsLoaded());
3297  g.DrawListSharedData.ClipRectFullscreen = ImVec4(0.0f, 0.0f, g.IO.DisplaySize.x, g.IO.DisplaySize.y);
3298  g.DrawListSharedData.CurveTessellationTol = g.Style.CurveTessellationTol;
3299 
3300  g.OverlayDrawList.Clear();
3301  g.OverlayDrawList.PushTextureID(g.IO.Fonts->TexID);
3302  g.OverlayDrawList.PushClipRectFullScreen();
3303  g.OverlayDrawList.Flags = (g.Style.AntiAliasedLines ? ImDrawListFlags_AntiAliasedLines : 0) | (g.Style.AntiAliasedFill ? ImDrawListFlags_AntiAliasedFill : 0);
3304 
3305  // Mark rendering data as invalid to prevent user who may have a handle on it to use it
3306  g.DrawData.Clear();
3307 
3308  // Clear reference to active widget if the widget isn't alive anymore
3309  if (!g.HoveredIdPreviousFrame)
3310  g.HoveredIdTimer = 0.0f;
3311  g.HoveredIdPreviousFrame = g.HoveredId;
3312  g.HoveredId = 0;
3313  g.HoveredIdAllowOverlap = false;
3314  if (!g.ActiveIdIsAlive && g.ActiveIdPreviousFrame == g.ActiveId && g.ActiveId != 0)
3315  ClearActiveID();
3316  if (g.ActiveId)
3317  g.ActiveIdTimer += g.IO.DeltaTime;
3318  g.ActiveIdPreviousFrame = g.ActiveId;
3319  g.ActiveIdIsAlive = false;
3320  g.ActiveIdIsJustActivated = false;
3321  if (g.ScalarAsInputTextId && g.ActiveId != g.ScalarAsInputTextId)
3322  g.ScalarAsInputTextId = 0;
3323 
3324  // Elapse drag & drop payload
3325  if (g.DragDropActive && g.DragDropPayload.DataFrameCount + 1 < g.FrameCount)
3326  {
3327  ClearDragDrop();
3328  g.DragDropPayloadBufHeap.clear();
3329  memset(&g.DragDropPayloadBufLocal, 0, sizeof(g.DragDropPayloadBufLocal));
3330  }
3331  g.DragDropAcceptIdPrev = g.DragDropAcceptIdCurr;
3332  g.DragDropAcceptIdCurr = 0;
3333  g.DragDropAcceptIdCurrRectSurface = FLT_MAX;
3334 
3335  // Update keyboard input state
3336  memcpy(g.IO.KeysDownDurationPrev, g.IO.KeysDownDuration, sizeof(g.IO.KeysDownDuration));
3337  for (int i = 0; i < IM_ARRAYSIZE(g.IO.KeysDown); i++)
3338  g.IO.KeysDownDuration[i] = g.IO.KeysDown[i] ? (g.IO.KeysDownDuration[i] < 0.0f ? 0.0f : g.IO.KeysDownDuration[i] + g.IO.DeltaTime) : -1.0f;
3339 
3340  // Update gamepad/keyboard directional navigation
3341  NavUpdate();
3342 
3343  // Update mouse input state
3344  // If mouse just appeared or disappeared (usually denoted by -FLT_MAX component, but in reality we test for -256000.0f) we cancel out movement in MouseDelta
3345  if (IsMousePosValid(&g.IO.MousePos) && IsMousePosValid(&g.IO.MousePosPrev))
3346  g.IO.MouseDelta = g.IO.MousePos - g.IO.MousePosPrev;
3347  else
3348  g.IO.MouseDelta = ImVec2(0.0f, 0.0f);
3349  if (g.IO.MouseDelta.x != 0.0f || g.IO.MouseDelta.y != 0.0f)
3350  g.NavDisableMouseHover = false;
3351 
3352  g.IO.MousePosPrev = g.IO.MousePos;
3353  for (int i = 0; i < IM_ARRAYSIZE(g.IO.MouseDown); i++)
3354  {
3355  g.IO.MouseClicked[i] = g.IO.MouseDown[i] && g.IO.MouseDownDuration[i] < 0.0f;
3356  g.IO.MouseReleased[i] = !g.IO.MouseDown[i] && g.IO.MouseDownDuration[i] >= 0.0f;
3357  g.IO.MouseDownDurationPrev[i] = g.IO.MouseDownDuration[i];
3358  g.IO.MouseDownDuration[i] = g.IO.MouseDown[i] ? (g.IO.MouseDownDuration[i] < 0.0f ? 0.0f : g.IO.MouseDownDuration[i] + g.IO.DeltaTime) : -1.0f;
3359  g.IO.MouseDoubleClicked[i] = false;
3360  if (g.IO.MouseClicked[i])
3361  {
3362  if (g.Time - g.IO.MouseClickedTime[i] < g.IO.MouseDoubleClickTime)
3363  {
3364  if (ImLengthSqr(g.IO.MousePos - g.IO.MouseClickedPos[i]) < g.IO.MouseDoubleClickMaxDist * g.IO.MouseDoubleClickMaxDist)
3365  g.IO.MouseDoubleClicked[i] = true;
3366  g.IO.MouseClickedTime[i] = -FLT_MAX; // so the third click isn't turned into a double-click
3367  }
3368  else
3369  {
3370  g.IO.MouseClickedTime[i] = g.Time;
3371  }
3372  g.IO.MouseClickedPos[i] = g.IO.MousePos;
3373  g.IO.MouseDragMaxDistanceAbs[i] = ImVec2(0.0f, 0.0f);
3374  g.IO.MouseDragMaxDistanceSqr[i] = 0.0f;
3375  }
3376  else if (g.IO.MouseDown[i])
3377  {
3378  ImVec2 mouse_delta = g.IO.MousePos - g.IO.MouseClickedPos[i];
3379  g.IO.MouseDragMaxDistanceAbs[i].x = ImMax(g.IO.MouseDragMaxDistanceAbs[i].x, mouse_delta.x < 0.0f ? -mouse_delta.x : mouse_delta.x);
3380  g.IO.MouseDragMaxDistanceAbs[i].y = ImMax(g.IO.MouseDragMaxDistanceAbs[i].y, mouse_delta.y < 0.0f ? -mouse_delta.y : mouse_delta.y);
3381  g.IO.MouseDragMaxDistanceSqr[i] = ImMax(g.IO.MouseDragMaxDistanceSqr[i], ImLengthSqr(mouse_delta));
3382  }
3383  if (g.IO.MouseClicked[i]) // Clicking any mouse button reactivate mouse hovering which may have been deactivated by gamepad/keyboard navigation
3384  g.NavDisableMouseHover = false;
3385  }
3386 
3387  // Calculate frame-rate for the user, as a purely luxurious feature
3388  g.FramerateSecPerFrameAccum += g.IO.DeltaTime - g.FramerateSecPerFrame[g.FramerateSecPerFrameIdx];
3389  g.FramerateSecPerFrame[g.FramerateSecPerFrameIdx] = g.IO.DeltaTime;
3390  g.FramerateSecPerFrameIdx = (g.FramerateSecPerFrameIdx + 1) % IM_ARRAYSIZE(g.FramerateSecPerFrame);
3391  g.IO.Framerate = 1.0f / (g.FramerateSecPerFrameAccum / (float)IM_ARRAYSIZE(g.FramerateSecPerFrame));
3392 
3393  // Handle user moving window with mouse (at the beginning of the frame to avoid input lag or sheering)
3395 
3396  // Delay saving settings so we don't spam disk too much
3397  if (g.SettingsDirtyTimer > 0.0f)
3398  {
3399  g.SettingsDirtyTimer -= g.IO.DeltaTime;
3400  if (g.SettingsDirtyTimer <= 0.0f)
3401  SaveIniSettingsToDisk(g.IO.IniFilename);
3402  }
3403 
3404  // Find the window we are hovering
3405  // - Child windows can extend beyond the limit of their parent so we need to derive HoveredRootWindow from HoveredWindow.
3406  // - When moving a window we can skip the search, which also conveniently bypasses the fact that window->WindowRectClipped is lagging as this point.
3407  // - We also support the moved window toggling the NoInputs flag after moving has started in order to be able to detect windows below it, which is useful for e.g. docking mechanisms.
3408  g.HoveredWindow = (g.MovingWindow && !(g.MovingWindow->Flags & ImGuiWindowFlags_NoInputs)) ? g.MovingWindow : FindHoveredWindow();
3409  g.HoveredRootWindow = g.HoveredWindow ? g.HoveredWindow->RootWindow : NULL;
3410 
3411  ImGuiWindow* modal_window = GetFrontMostModalRootWindow();
3412  if (modal_window != NULL)
3413  {
3414  g.ModalWindowDarkeningRatio = ImMin(g.ModalWindowDarkeningRatio + g.IO.DeltaTime * 6.0f, 1.0f);
3415  if (g.HoveredRootWindow && !IsWindowChildOf(g.HoveredRootWindow, modal_window))
3416  g.HoveredRootWindow = g.HoveredWindow = NULL;
3417  }
3418  else
3419  {
3420  g.ModalWindowDarkeningRatio = 0.0f;
3421  }
3422 
3423  // Update the WantCaptureMouse/WantCaptureKeyboard flags, so user can capture/discard the inputs away from the rest of their application.
3424  // When clicking outside of a window we assume the click is owned by the application and won't request capture. We need to track click ownership.
3425  int mouse_earliest_button_down = -1;
3426  bool mouse_any_down = false;
3427  for (int i = 0; i < IM_ARRAYSIZE(g.IO.MouseDown); i++)
3428  {
3429  if (g.IO.MouseClicked[i])
3430  g.IO.MouseDownOwned[i] = (g.HoveredWindow != NULL) || (!g.OpenPopupStack.empty());
3431  mouse_any_down |= g.IO.MouseDown[i];
3432  if (g.IO.MouseDown[i])
3433  if (mouse_earliest_button_down == -1 || g.IO.MouseClickedTime[i] < g.IO.MouseClickedTime[mouse_earliest_button_down])
3434  mouse_earliest_button_down = i;
3435  }
3436  bool mouse_avail_to_imgui = (mouse_earliest_button_down == -1) || g.IO.MouseDownOwned[mouse_earliest_button_down];
3437  if (g.WantCaptureMouseNextFrame != -1)
3438  g.IO.WantCaptureMouse = (g.WantCaptureMouseNextFrame != 0);
3439  else
3440  g.IO.WantCaptureMouse = (mouse_avail_to_imgui && (g.HoveredWindow != NULL || mouse_any_down)) || (!g.OpenPopupStack.empty());
3441 
3442  if (g.WantCaptureKeyboardNextFrame != -1)
3443  g.IO.WantCaptureKeyboard = (g.WantCaptureKeyboardNextFrame != 0);
3444  else
3445  g.IO.WantCaptureKeyboard = (g.ActiveId != 0) || (modal_window != NULL);
3446  if (g.IO.NavActive && (g.IO.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard) && !(g.IO.ConfigFlags & ImGuiConfigFlags_NavNoCaptureKeyboard))
3447  g.IO.WantCaptureKeyboard = true;
3448 
3449  g.IO.WantTextInput = (g.WantTextInputNextFrame != -1) ? (g.WantTextInputNextFrame != 0) : 0;
3450  g.MouseCursor = ImGuiMouseCursor_Arrow;
3451  g.WantCaptureMouseNextFrame = g.WantCaptureKeyboardNextFrame = g.WantTextInputNextFrame = -1;
3452  g.OsImePosRequest = ImVec2(1.0f, 1.0f); // OS Input Method Editor showing on top-left of our window by default
3453 
3454  // If mouse was first clicked outside of ImGui bounds we also cancel out hovering.
3455  // FIXME: For patterns of drag and drop across OS windows, we may need to rework/remove this test (first committed 311c0ca9 on 2015/02)
3456  bool mouse_dragging_extern_payload = g.DragDropActive && (g.DragDropSourceFlags & ImGuiDragDropFlags_SourceExtern) != 0;
3457  if (!mouse_avail_to_imgui && !mouse_dragging_extern_payload)
3458  g.HoveredWindow = g.HoveredRootWindow = NULL;
3459 
3460  // Mouse wheel scrolling, scale
3461  if (g.HoveredWindow && !g.HoveredWindow->Collapsed && (g.IO.MouseWheel != 0.0f || g.IO.MouseWheelH != 0.0f))
3462  {
3463  // If a child window has the ImGuiWindowFlags_NoScrollWithMouse flag, we give a chance to scroll its parent (unless either ImGuiWindowFlags_NoInputs or ImGuiWindowFlags_NoScrollbar are also set).
3464  ImGuiWindow* window = g.HoveredWindow;
3465  ImGuiWindow* scroll_window = window;
3466  while ((scroll_window->Flags & ImGuiWindowFlags_ChildWindow) && (scroll_window->Flags & ImGuiWindowFlags_NoScrollWithMouse) && !(scroll_window->Flags & ImGuiWindowFlags_NoScrollbar) && !(scroll_window->Flags & ImGuiWindowFlags_NoInputs) && scroll_window->ParentWindow)
3467  scroll_window = scroll_window->ParentWindow;
3468  const bool scroll_allowed = !(scroll_window->Flags & ImGuiWindowFlags_NoScrollWithMouse) && !(scroll_window->Flags & ImGuiWindowFlags_NoInputs);
3469 
3470  if (g.IO.MouseWheel != 0.0f)
3471  {
3472  if (g.IO.KeyCtrl && g.IO.FontAllowUserScaling)
3473  {
3474  // Zoom / Scale window
3475  const float new_font_scale = ImClamp(window->FontWindowScale + g.IO.MouseWheel * 0.10f, 0.50f, 2.50f);
3476  const float scale = new_font_scale / window->FontWindowScale;
3477  window->FontWindowScale = new_font_scale;
3478 
3479  const ImVec2 offset = window->Size * (1.0f - scale) * (g.IO.MousePos - window->Pos) / window->Size;
3480  window->Pos += offset;
3481  window->PosFloat += offset;
3482  window->Size *= scale;
3483  window->SizeFull *= scale;
3484  }
3485  else if (!g.IO.KeyCtrl && scroll_allowed)
3486  {
3487  // Mouse wheel vertical scrolling
3488  float scroll_amount = 5 * scroll_window->CalcFontSize();
3489  scroll_amount = (float)(int)ImMin(scroll_amount, (scroll_window->ContentsRegionRect.GetHeight() + scroll_window->WindowPadding.y * 2.0f) * 0.67f);
3490  SetWindowScrollY(scroll_window, scroll_window->Scroll.y - g.IO.MouseWheel * scroll_amount);
3491  }
3492  }
3493  if (g.IO.MouseWheelH != 0.0f && scroll_allowed)
3494  {
3495  // Mouse wheel horizontal scrolling (for hardware that supports it)
3496  float scroll_amount = scroll_window->CalcFontSize();
3497  if (!g.IO.KeyCtrl && !(window->Flags & ImGuiWindowFlags_NoScrollWithMouse))
3498  SetWindowScrollX(window, window->Scroll.x - g.IO.MouseWheelH * scroll_amount);
3499  }
3500  }
3501 
3502  // Pressing TAB activate widget focus
3503  if (g.ActiveId == 0 && g.NavWindow != NULL && g.NavWindow->Active && !(g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs) && !g.IO.KeyCtrl && IsKeyPressedMap(ImGuiKey_Tab, false))
3504  {
3505  if (g.NavId != 0 && g.NavIdTabCounter != INT_MAX)
3506  g.NavWindow->FocusIdxTabRequestNext = g.NavIdTabCounter + 1 + (g.IO.KeyShift ? -1 : 1);
3507  else
3508  g.NavWindow->FocusIdxTabRequestNext = g.IO.KeyShift ? -1 : 0;
3509  }
3510  g.NavIdTabCounter = INT_MAX;
3511 
3512  // Mark all windows as not visible
3513  for (int i = 0; i != g.Windows.Size; i++)
3514  {
3515  ImGuiWindow* window = g.Windows[i];
3516  window->WasActive = window->Active;
3517  window->Active = false;
3518  window->WriteAccessed = false;
3519  }
3520 
3521  // Closing the focused window restore focus to the first active root window in descending z-order
3522  if (g.NavWindow && !g.NavWindow->WasActive)
3524 
3525  // No window should be open at the beginning of the frame.
3526  // But in order to allow the user to call NewFrame() multiple times without calling Render(), we are doing an explicit clear.
3527  g.CurrentWindowStack.resize(0);
3528  g.CurrentPopupStack.resize(0);
3529  ClosePopupsOverWindow(g.NavWindow);
3530 
3531  // Create implicit window - we will only render it if the user has added something to it.
3532  // We don't use "Debug" to avoid colliding with user trying to create a "Debug" window with custom flags.
3534  Begin("Debug##Default");
3535 }
3536 
3538 {
3540  if (!settings)
3541  settings = AddWindowSettings(name);
3542  return (void*)settings;
3543 }
3544 
3545 static void SettingsHandlerWindow_ReadLine(ImGuiContext*, ImGuiSettingsHandler*, void* entry, const char* line)
3546 {
3547  ImGuiWindowSettings* settings = (ImGuiWindowSettings*)entry;
3548  float x, y;
3549  int i;
3550  if (sscanf(line, "Pos=%f,%f", &x, &y) == 2) settings->Pos = ImVec2(x, y);
3551  else if (sscanf(line, "Size=%f,%f", &x, &y) == 2) settings->Size = ImMax(ImVec2(x, y), GImGui->Style.WindowMinSize);
3552  else if (sscanf(line, "Collapsed=%d", &i) == 1) settings->Collapsed = (i != 0);
3553 }
3554 
3556 {
3557  // Gather data from windows that were active during this session
3558  ImGuiContext& g = *imgui_ctx;
3559  for (int i = 0; i != g.Windows.Size; i++)
3560  {
3561  ImGuiWindow* window = g.Windows[i];
3563  continue;
3564  ImGuiWindowSettings* settings = ImGui::FindWindowSettings(window->ID);
3565  if (!settings)
3566  settings = AddWindowSettings(window->Name);
3567  settings->Pos = window->Pos;
3568  settings->Size = window->SizeFull;
3569  settings->Collapsed = window->Collapsed;
3570  }
3571 
3572  // Write a buffer
3573  // If a window wasn't opened in this session we preserve its settings
3574  buf->reserve(buf->size() + g.SettingsWindows.Size * 96); // ballpark reserve
3575  for (int i = 0; i != g.SettingsWindows.Size; i++)
3576  {
3577  const ImGuiWindowSettings* settings = &g.SettingsWindows[i];
3578  if (settings->Pos.x == FLT_MAX)
3579  continue;
3580  const char* name = settings->Name;
3581  if (const char* p = strstr(name, "###")) // Skip to the "###" marker if any. We don't skip past to match the behavior of GetID()
3582  name = p;
3583  buf->appendf("[%s][%s]\n", handler->TypeName, name);
3584  buf->appendf("Pos=%d,%d\n", (int)settings->Pos.x, (int)settings->Pos.y);
3585  buf->appendf("Size=%d,%d\n", (int)settings->Size.x, (int)settings->Size.y);
3586  buf->appendf("Collapsed=%d\n", settings->Collapsed);
3587  buf->appendf("\n");
3588  }
3589 }
3590 
3592 {
3593  ImGuiContext& g = *context;
3594  IM_ASSERT(!g.Initialized && !g.SettingsLoaded);
3595  g.LogClipboard = IM_NEW(ImGuiTextBuffer)();
3596 
3597  // Add .ini handle for ImGuiWindow type
3598  ImGuiSettingsHandler ini_handler;
3599  ini_handler.TypeName = "Window";
3600  ini_handler.TypeHash = ImHash("Window", 0, 0);
3604  g.SettingsHandlers.push_front(ini_handler);
3605 
3606  g.Initialized = true;
3607 }
3608 
3609 // This function is merely here to free heap allocations.
3611 {
3612  ImGuiContext& g = *context;
3613 
3614  // The fonts atlas can be used prior to calling NewFrame(), so we clear it even if g.Initialized is FALSE (which would happen if we never called NewFrame)
3615  if (g.IO.Fonts && g.FontAtlasOwnedByContext)
3616  IM_DELETE(g.IO.Fonts);
3617 
3618  // Cleanup of other data are conditional on actually having initialize ImGui.
3619  if (!g.Initialized)
3620  return;
3621 
3622  SaveIniSettingsToDisk(g.IO.IniFilename);
3623 
3624  // Clear everything else
3625  for (int i = 0; i < g.Windows.Size; i++)
3626  IM_DELETE(g.Windows[i]);
3627  g.Windows.clear();
3628  g.WindowsSortBuffer.clear();
3629  g.CurrentWindow = NULL;
3630  g.CurrentWindowStack.clear();
3631  g.WindowsById.Clear();
3632  g.NavWindow = NULL;
3633  g.HoveredWindow = NULL;
3634  g.HoveredRootWindow = NULL;
3635  g.ActiveIdWindow = NULL;
3636  g.MovingWindow = NULL;
3637  for (int i = 0; i < g.SettingsWindows.Size; i++)
3638  IM_DELETE(g.SettingsWindows[i].Name);
3639  g.ColorModifiers.clear();
3640  g.StyleModifiers.clear();
3641  g.FontStack.clear();
3642  g.OpenPopupStack.clear();
3643  g.CurrentPopupStack.clear();
3644  g.DrawDataBuilder.ClearFreeMemory();
3645  g.OverlayDrawList.ClearFreeMemory();
3646  g.PrivateClipboard.clear();
3647  g.InputTextState.Text.clear();
3648  g.InputTextState.InitialText.clear();
3649  g.InputTextState.TempTextBuffer.clear();
3650 
3651  g.SettingsWindows.clear();
3652  g.SettingsHandlers.clear();
3653 
3654  if (g.LogFile && g.LogFile != stdout)
3655  {
3656  fclose(g.LogFile);
3657  g.LogFile = NULL;
3658  }
3659  if (g.LogClipboard)
3660  IM_DELETE(g.LogClipboard);
3661 
3662  g.Initialized = false;
3663 }
3664 
3666 {
3667  ImGuiContext& g = *GImGui;
3668  for (int i = 0; i != g.SettingsWindows.Size; i++)
3669  if (g.SettingsWindows[i].Id == id)
3670  return &g.SettingsWindows[i];
3671  return NULL;
3672 }
3673 
3675 {
3676  ImGuiContext& g = *GImGui;
3678  ImGuiWindowSettings* settings = &g.SettingsWindows.back();
3679  settings->Name = ImStrdup(name);
3680  settings->Id = ImHash(name, 0);
3681  return settings;
3682 }
3683 
3684 static void LoadIniSettingsFromDisk(const char* ini_filename)
3685 {
3686  if (!ini_filename)
3687  return;
3688  char* file_data = (char*)ImFileLoadToMemory(ini_filename, "rb", NULL, +1);
3689  if (!file_data)
3690  return;
3691  LoadIniSettingsFromMemory(file_data);
3692  ImGui::MemFree(file_data);
3693 }
3694 
3696 {
3697  ImGuiContext& g = *GImGui;
3698  const ImGuiID type_hash = ImHash(type_name, 0, 0);
3699  for (int handler_n = 0; handler_n < g.SettingsHandlers.Size; handler_n++)
3700  if (g.SettingsHandlers[handler_n].TypeHash == type_hash)
3701  return &g.SettingsHandlers[handler_n];
3702  return NULL;
3703 }
3704 
3705 // Zero-tolerance, no error reporting, cheap .ini parsing
3706 static void LoadIniSettingsFromMemory(const char* buf_readonly)
3707 {
3708  // For convenience and to make the code simpler, we'll write zero terminators inside the buffer. So let's create a writable copy.
3709  char* buf = ImStrdup(buf_readonly);
3710  char* buf_end = buf + strlen(buf);
3711 
3712  ImGuiContext& g = *GImGui;
3713  void* entry_data = NULL;
3714  ImGuiSettingsHandler* entry_handler = NULL;
3715 
3716  char* line_end = NULL;
3717  for (char* line = buf; line < buf_end; line = line_end + 1)
3718  {
3719  // Skip new lines markers, then find end of the line
3720  while (*line == '\n' || *line == '\r')
3721  line++;
3722  line_end = line;
3723  while (line_end < buf_end && *line_end != '\n' && *line_end != '\r')
3724  line_end++;
3725  line_end[0] = 0;
3726 
3727  if (line[0] == '[' && line_end > line && line_end[-1] == ']')
3728  {
3729  // Parse "[Type][Name]". Note that 'Name' can itself contains [] characters, which is acceptable with the current format and parsing code.
3730  line_end[-1] = 0;
3731  const char* name_end = line_end - 1;
3732  const char* type_start = line + 1;
3733  char* type_end = ImStrchrRange(type_start, name_end, ']');
3734  const char* name_start = type_end ? ImStrchrRange(type_end + 1, name_end, '[') : NULL;
3735  if (!type_end || !name_start)
3736  {
3737  name_start = type_start; // Import legacy entries that have no type
3738  type_start = "Window";
3739  }
3740  else
3741  {
3742  *type_end = 0; // Overwrite first ']'
3743  name_start++; // Skip second '['
3744  }
3745  entry_handler = ImGui::FindSettingsHandler(type_start);
3746  entry_data = entry_handler ? entry_handler->ReadOpenFn(&g, entry_handler, name_start) : NULL;
3747  }
3748  else if (entry_handler != NULL && entry_data != NULL)
3749  {
3750  // Let type handler parse the line
3751  entry_handler->ReadLineFn(&g, entry_handler, entry_data, line);
3752  }
3753  }
3755  g.SettingsLoaded = true;
3756 }
3757 
3758 static void SaveIniSettingsToDisk(const char* ini_filename)
3759 {
3760  ImGuiContext& g = *GImGui;
3761  g.SettingsDirtyTimer = 0.0f;
3762  if (!ini_filename)
3763  return;
3764 
3767 
3768  FILE* f = ImFileOpen(ini_filename, "wt");
3769  if (!f)
3770  return;
3771  fwrite(buf.Data, sizeof(char), (size_t)buf.Size, f);
3772  fclose(f);
3773 }
3774 
3776 {
3777  ImGuiContext& g = *GImGui;
3778  g.SettingsDirtyTimer = 0.0f;
3779 
3781  for (int handler_n = 0; handler_n < g.SettingsHandlers.Size; handler_n++)
3782  {
3783  ImGuiSettingsHandler* handler = &g.SettingsHandlers[handler_n];
3784  handler->WriteAllFn(&g, handler, &buf);
3785  }
3786 
3787  buf.Buf.pop_back(); // Remove extra zero-terminator used by ImGuiTextBuffer
3788  out_buf.swap(buf.Buf);
3789 }
3790 
3792 {
3793  ImGuiContext& g = *GImGui;
3794  if (g.SettingsDirtyTimer <= 0.0f)
3795  g.SettingsDirtyTimer = g.IO.IniSavingRate;
3796 }
3797 
3798 static void MarkIniSettingsDirty(ImGuiWindow* window)
3799 {
3800  ImGuiContext& g = *GImGui;
3801  if (!(window->Flags & ImGuiWindowFlags_NoSavedSettings))
3802  if (g.SettingsDirtyTimer <= 0.0f)
3803  g.SettingsDirtyTimer = g.IO.IniSavingRate;
3804 }
3805 
3806 // FIXME: Add a more explicit sort order in the window structure.
3807 static int IMGUI_CDECL ChildWindowComparer(const void* lhs, const void* rhs)
3808 {
3809  const ImGuiWindow* a = *(const ImGuiWindow**)lhs;
3810  const ImGuiWindow* b = *(const ImGuiWindow**)rhs;
3811  if (int d = (a->Flags & ImGuiWindowFlags_Popup) - (b->Flags & ImGuiWindowFlags_Popup))
3812  return d;
3813  if (int d = (a->Flags & ImGuiWindowFlags_Tooltip) - (b->Flags & ImGuiWindowFlags_Tooltip))
3814  return d;
3815  return (a->BeginOrderWithinParent - b->BeginOrderWithinParent);
3816 }
3817 
3818 static void AddWindowToSortedBuffer(ImVector<ImGuiWindow*>* out_sorted_windows, ImGuiWindow* window)
3819 {
3820  out_sorted_windows->push_back(window);
3821  if (window->Active)
3822  {
3823  int count = window->DC.ChildWindows.Size;
3824  if (count > 1)
3825  qsort(window->DC.ChildWindows.begin(), (size_t)count, sizeof(ImGuiWindow*), ChildWindowComparer);
3826  for (int i = 0; i < count; i++)
3827  {
3828  ImGuiWindow* child = window->DC.ChildWindows[i];
3829  if (child->Active)
3830  AddWindowToSortedBuffer(out_sorted_windows, child);
3831  }
3832  }
3833 }
3834 
3835 static void AddDrawListToDrawData(ImVector<ImDrawList*>* out_render_list, ImDrawList* draw_list)
3836 {
3837  if (draw_list->CmdBuffer.empty())
3838  return;
3839 
3840  // Remove trailing command if unused
3841  ImDrawCmd& last_cmd = draw_list->CmdBuffer.back();
3842  if (last_cmd.ElemCount == 0 && last_cmd.UserCallback == NULL)
3843  {
3844  draw_list->CmdBuffer.pop_back();
3845  if (draw_list->CmdBuffer.empty())
3846  return;
3847  }
3848 
3849  // Draw list sanity check. Detect mismatch between PrimReserve() calls and incrementing _VtxCurrentIdx, _VtxWritePtr etc. May trigger for you if you are using PrimXXX functions incorrectly.
3850  IM_ASSERT(draw_list->VtxBuffer.Size == 0 || draw_list->_VtxWritePtr == draw_list->VtxBuffer.Data + draw_list->VtxBuffer.Size);
3851  IM_ASSERT(draw_list->IdxBuffer.Size == 0 || draw_list->_IdxWritePtr == draw_list->IdxBuffer.Data + draw_list->IdxBuffer.Size);
3852  IM_ASSERT((int)draw_list->_VtxCurrentIdx == draw_list->VtxBuffer.Size);
3853 
3854  // Check that draw_list doesn't use more vertices than indexable (default ImDrawIdx = unsigned short = 2 bytes = 64K vertices per ImDrawList = per window)
3855  // If this assert triggers because you are drawing lots of stuff manually:
3856  // A) Make sure you are coarse clipping, because ImDrawList let all your vertices pass. You can use the Metrics window to inspect draw list contents.
3857  // B) If you need/want meshes with more than 64K vertices, uncomment the '#define ImDrawIdx unsigned int' line in imconfig.h to set the index size to 4 bytes.
3858  // You'll need to handle the 4-bytes indices to your renderer. For example, the OpenGL example code detect index size at compile-time by doing:
3859  // glDrawElements(GL_TRIANGLES, (GLsizei)pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, idx_buffer_offset);
3860  // Your own engine or render API may use different parameters or function calls to specify index sizes. 2 and 4 bytes indices are generally supported by most API.
3861  // C) If for some reason you cannot use 4 bytes indices or don't want to, a workaround is to call BeginChild()/EndChild() before reaching the 64K limit to split your draw commands in multiple draw lists.
3862  if (sizeof(ImDrawIdx) == 2)
3863  IM_ASSERT(draw_list->_VtxCurrentIdx < (1 << 16) && "Too many vertices in ImDrawList using 16-bit indices. Read comment above");
3864 
3865  out_render_list->push_back(draw_list);
3866 }
3867 
3868 static void AddWindowToDrawData(ImVector<ImDrawList*>* out_render_list, ImGuiWindow* window)
3869 {
3870  AddDrawListToDrawData(out_render_list, window->DrawList);
3871  for (int i = 0; i < window->DC.ChildWindows.Size; i++)
3872  {
3873  ImGuiWindow* child = window->DC.ChildWindows[i];
3874  if (child->Active && child->HiddenFrames <= 0) // clipped children may have been marked not active
3875  AddWindowToDrawData(out_render_list, child);
3876  }
3877 }
3878 
3880 {
3881  ImGuiContext& g = *GImGui;
3883  if (window->Flags & ImGuiWindowFlags_Tooltip)
3884  AddWindowToDrawData(&g.DrawDataBuilder.Layers[1], window);
3885  else
3886  AddWindowToDrawData(&g.DrawDataBuilder.Layers[0], window);
3887 }
3888 
3890 {
3891  int n = Layers[0].Size;
3892  int size = n;
3893  for (int i = 1; i < IM_ARRAYSIZE(Layers); i++)
3894  size += Layers[i].Size;
3895  Layers[0].resize(size);
3896  for (int layer_n = 1; layer_n < IM_ARRAYSIZE(Layers); layer_n++)
3897  {
3898  ImVector<ImDrawList*>& layer = Layers[layer_n];
3899  if (layer.empty())
3900  continue;
3901  memcpy(&Layers[0][n], &layer[0], layer.Size * sizeof(ImDrawList*));
3902  n += layer.Size;
3903  layer.resize(0);
3904  }
3905 }
3906 
3907 static void SetupDrawData(ImVector<ImDrawList*>* draw_lists, ImDrawData* out_draw_data)
3908 {
3909  out_draw_data->Valid = true;
3910  out_draw_data->CmdLists = (draw_lists->Size > 0) ? draw_lists->Data : NULL;
3911  out_draw_data->CmdListsCount = draw_lists->Size;
3912  out_draw_data->TotalVtxCount = out_draw_data->TotalIdxCount = 0;
3913  for (int n = 0; n < draw_lists->Size; n++)
3914  {
3915  out_draw_data->TotalVtxCount += draw_lists->Data[n]->VtxBuffer.Size;
3916  out_draw_data->TotalIdxCount += draw_lists->Data[n]->IdxBuffer.Size;
3917  }
3918 }
3919 
3920 // When using this function it is sane to ensure that float are perfectly rounded to integer values, to that e.g. (int)(max.x-min.x) in user's render produce correct result.
3921 void ImGui::PushClipRect(const ImVec2& clip_rect_min, const ImVec2& clip_rect_max, bool intersect_with_current_clip_rect)
3922 {
3923  ImGuiWindow* window = GetCurrentWindow();
3924  window->DrawList->PushClipRect(clip_rect_min, clip_rect_max, intersect_with_current_clip_rect);
3925  window->ClipRect = window->DrawList->_ClipRectStack.back();
3926 }
3927 
3929 {
3930  ImGuiWindow* window = GetCurrentWindow();
3931  window->DrawList->PopClipRect();
3932  window->ClipRect = window->DrawList->_ClipRectStack.back();
3933 }
3934 
3935 // This is normally called by Render(). You may want to call it directly if you want to avoid calling Render() but the gain will be very minimal.
3937 {
3938  ImGuiContext& g = *GImGui;
3939  IM_ASSERT(g.Initialized); // Forgot to call ImGui::NewFrame()
3940  if (g.FrameCountEnded == g.FrameCount) // Don't process EndFrame() multiple times.
3941  return;
3942 
3943  // Notify OS when our Input Method Editor cursor has moved (e.g. CJK inputs using Microsoft IME)
3944  if (g.IO.ImeSetInputScreenPosFn && ImLengthSqr(g.OsImePosRequest - g.OsImePosSet) > 0.0001f)
3945  {
3946  g.IO.ImeSetInputScreenPosFn((int)g.OsImePosRequest.x, (int)g.OsImePosRequest.y);
3947  g.OsImePosSet = g.OsImePosRequest;
3948  }
3949 
3950  // Hide implicit "Debug" window if it hasn't been used
3951  IM_ASSERT(g.CurrentWindowStack.Size == 1); // Mismatched Begin()/End() calls
3952  if (g.CurrentWindow && !g.CurrentWindow->WriteAccessed)
3953  g.CurrentWindow->Active = false;
3954  End();
3955 
3956  if (g.ActiveId == 0 && g.HoveredId == 0)
3957  {
3958  if (!g.NavWindow || !g.NavWindow->Appearing) // Unless we just made a window/popup appear
3959  {
3960  // Click to focus window and start moving (after we're done with all our widgets)
3961  if (g.IO.MouseClicked[0])
3962  {
3963  if (g.HoveredRootWindow != NULL)
3964  {
3965  // Set ActiveId even if the _NoMove flag is set, without it dragging away from a window with _NoMove would activate hover on other windows.
3966  FocusWindow(g.HoveredWindow);
3967  SetActiveID(g.HoveredWindow->MoveId, g.HoveredWindow);
3968  g.NavDisableHighlight = true;
3969  g.ActiveIdClickOffset = g.IO.MousePos - g.HoveredRootWindow->Pos;
3970  if (!(g.HoveredWindow->Flags & ImGuiWindowFlags_NoMove) && !(g.HoveredRootWindow->Flags & ImGuiWindowFlags_NoMove))
3971  g.MovingWindow = g.HoveredWindow;
3972  }
3973  else if (g.NavWindow != NULL && GetFrontMostModalRootWindow() == NULL)
3974  {
3975  // Clicking on void disable focus
3976  FocusWindow(NULL);
3977  }
3978  }
3979 
3980  // With right mouse button we close popups without changing focus
3981  // (The left mouse button path calls FocusWindow which will lead NewFrame->ClosePopupsOverWindow to trigger)
3982  if (g.IO.MouseClicked[1])
3983  {
3984  // Find the top-most window between HoveredWindow and the front most Modal Window.
3985  // This is where we can trim the popup stack.
3987  bool hovered_window_above_modal = false;
3988  if (modal == NULL)
3989  hovered_window_above_modal = true;
3990  for (int i = g.Windows.Size - 1; i >= 0 && hovered_window_above_modal == false; i--)
3991  {
3992  ImGuiWindow* window = g.Windows[i];
3993  if (window == modal)
3994  break;
3995  if (window == g.HoveredWindow)
3996  hovered_window_above_modal = true;
3997  }
3998  ClosePopupsOverWindow(hovered_window_above_modal ? g.HoveredWindow : modal);
3999  }
4000  }
4001  }
4002 
4003  // Sort the window list so that all child windows are after their parent
4004  // We cannot do that on FocusWindow() because childs may not exist yet
4005  g.WindowsSortBuffer.resize(0);
4006  g.WindowsSortBuffer.reserve(g.Windows.Size);
4007  for (int i = 0; i != g.Windows.Size; i++)
4008  {
4009  ImGuiWindow* window = g.Windows[i];
4010  if (window->Active && (window->Flags & ImGuiWindowFlags_ChildWindow)) // if a child is active its parent will add it
4011  continue;
4012  AddWindowToSortedBuffer(&g.WindowsSortBuffer, window);
4013  }
4014 
4015  IM_ASSERT(g.Windows.Size == g.WindowsSortBuffer.Size); // we done something wrong
4016  g.Windows.swap(g.WindowsSortBuffer);
4017 
4018  // Clear Input data for next frame
4019  g.IO.MouseWheel = g.IO.MouseWheelH = 0.0f;
4020  memset(g.IO.InputCharacters, 0, sizeof(g.IO.InputCharacters));
4021  memset(g.IO.NavInputs, 0, sizeof(g.IO.NavInputs));
4022 
4023  g.FrameCountEnded = g.FrameCount;
4024 }
4025 
4027 {
4028  ImGuiContext& g = *GImGui;
4029  IM_ASSERT(g.Initialized); // Forgot to call ImGui::NewFrame()
4030 
4031  if (g.FrameCountEnded != g.FrameCount)
4032  ImGui::EndFrame();
4033  g.FrameCountRendered = g.FrameCount;
4034 
4035  // Skip render altogether if alpha is 0.0
4036  // Note that vertex buffers have been created and are wasted, so it is best practice that you don't create windows in the first place, or consistently respond to Begin() returning false.
4037  if (g.Style.Alpha > 0.0f)
4038  {
4039  // Gather windows to render
4040  g.IO.MetricsRenderVertices = g.IO.MetricsRenderIndices = g.IO.MetricsActiveWindows = 0;
4041  g.DrawDataBuilder.Clear();
4042  ImGuiWindow* window_to_render_front_most = (g.NavWindowingTarget && !(g.NavWindowingTarget->Flags & ImGuiWindowFlags_NoBringToFrontOnFocus)) ? g.NavWindowingTarget : NULL;
4043  for (int n = 0; n != g.Windows.Size; n++)
4044  {
4045  ImGuiWindow* window = g.Windows[n];
4046  if (window->Active && window->HiddenFrames <= 0 && (window->Flags & (ImGuiWindowFlags_ChildWindow)) == 0 && window != window_to_render_front_most)
4048  }
4049  if (window_to_render_front_most && window_to_render_front_most->Active && window_to_render_front_most->HiddenFrames <= 0) // NavWindowingTarget is always temporarily displayed as the front-most window
4050  AddWindowToDrawDataSelectLayer(window_to_render_front_most);
4051  g.DrawDataBuilder.FlattenIntoSingleLayer();
4052 
4053  // Draw software mouse cursor if requested
4054  ImVec2 offset, size, uv[4];
4055  if (g.IO.MouseDrawCursor && g.IO.Fonts->GetMouseCursorTexData(g.MouseCursor, &offset, &size, &uv[0], &uv[2]))
4056  {
4057  const ImVec2 pos = g.IO.MousePos - offset;
4058  const ImTextureID tex_id = g.IO.Fonts->TexID;
4059  const float sc = g.Style.MouseCursorScale;
4060  g.OverlayDrawList.PushTextureID(tex_id);
4061  g.OverlayDrawList.AddImage(tex_id, pos + ImVec2(1,0)*sc, pos+ImVec2(1,0)*sc + size*sc, uv[2], uv[3], IM_COL32(0,0,0,48)); // Shadow
4062  g.OverlayDrawList.AddImage(tex_id, pos + ImVec2(2,0)*sc, pos+ImVec2(2,0)*sc + size*sc, uv[2], uv[3], IM_COL32(0,0,0,48)); // Shadow
4063  g.OverlayDrawList.AddImage(tex_id, pos, pos + size*sc, uv[2], uv[3], IM_COL32(0,0,0,255)); // Black border
4064  g.OverlayDrawList.AddImage(tex_id, pos, pos + size*sc, uv[0], uv[1], IM_COL32(255,255,255,255)); // White fill
4065  g.OverlayDrawList.PopTextureID();
4066  }
4067  if (!g.OverlayDrawList.VtxBuffer.empty())
4068  AddDrawListToDrawData(&g.DrawDataBuilder.Layers[0], &g.OverlayDrawList);
4069 
4070  // Setup ImDrawData structure for end-user
4071  SetupDrawData(&g.DrawDataBuilder.Layers[0], &g.DrawData);
4072  g.IO.MetricsRenderVertices = g.DrawData.TotalVtxCount;
4073  g.IO.MetricsRenderIndices = g.DrawData.TotalIdxCount;
4074 
4075  // Render. If user hasn't set a callback then they may retrieve the draw data via GetDrawData()
4076 #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
4077  if (g.DrawData.CmdListsCount > 0 && g.IO.RenderDrawListsFn != NULL)
4078  g.IO.RenderDrawListsFn(&g.DrawData);
4079 #endif
4080  }
4081 }
4082 
4083 const char* ImGui::FindRenderedTextEnd(const char* text, const char* text_end)
4084 {
4085  const char* text_display_end = text;
4086  if (!text_end)
4087  text_end = (const char*)-1;
4088 
4089  while (text_display_end < text_end && *text_display_end != '\0' && (text_display_end[0] != '#' || text_display_end[1] != '#'))
4090  text_display_end++;
4091  return text_display_end;
4092 }
4093 
4094 // Pass text data straight to log (without being displayed)
4095 void ImGui::LogText(const char* fmt, ...)
4096 {
4097  ImGuiContext& g = *GImGui;
4098  if (!g.LogEnabled)
4099  return;
4100 
4101  va_list args;
4102  va_start(args, fmt);
4103  if (g.LogFile)
4104  {
4105  vfprintf(g.LogFile, fmt, args);
4106  }
4107  else
4108  {
4109  g.LogClipboard->appendfv(fmt, args);
4110  }
4111  va_end(args);
4112 }
4113 
4114 // Internal version that takes a position to decide on newline placement and pad items according to their depth.
4115 // We split text into individual lines to add current tree level padding
4116 static void LogRenderedText(const ImVec2* ref_pos, const char* text, const char* text_end = NULL)
4117 {
4118  ImGuiContext& g = *GImGui;
4119  ImGuiWindow* window = g.CurrentWindow;
4120 
4121  if (!text_end)
4122  text_end = ImGui::FindRenderedTextEnd(text, text_end);
4123 
4124  const bool log_new_line = ref_pos && (ref_pos->y > window->DC.LogLinePosY + 1);
4125  if (ref_pos)
4126  window->DC.LogLinePosY = ref_pos->y;
4127 
4128  const char* text_remaining = text;
4129  if (g.LogStartDepth > window->DC.TreeDepth) // Re-adjust padding if we have popped out of our starting depth
4130  g.LogStartDepth = window->DC.TreeDepth;
4131  const int tree_depth = (window->DC.TreeDepth - g.LogStartDepth);
4132  for (;;)
4133  {
4134  // Split the string. Each new line (after a '\n') is followed by spacing corresponding to the current depth of our log entry.
4135  const char* line_end = text_remaining;
4136  while (line_end < text_end)
4137  if (*line_end == '\n')
4138  break;
4139  else
4140  line_end++;
4141  if (line_end >= text_end)
4142  line_end = NULL;
4143 
4144  const bool is_first_line = (text == text_remaining);
4145  bool is_last_line = false;
4146  if (line_end == NULL)
4147  {
4148  is_last_line = true;
4149  line_end = text_end;
4150  }
4151  if (line_end != NULL && !(is_last_line && (line_end - text_remaining)==0))
4152  {
4153  const int char_count = (int)(line_end - text_remaining);
4154  if (log_new_line || !is_first_line)
4155  ImGui::LogText(IM_NEWLINE "%*s%.*s", tree_depth*4, "", char_count, text_remaining);
4156  else
4157  ImGui::LogText(" %.*s", char_count, text_remaining);
4158  }
4159 
4160  if (is_last_line)
4161  break;
4162  text_remaining = line_end + 1;
4163  }
4164 }
4165 
4166 // Internal ImGui functions to render text
4167 // RenderText***() functions calls ImDrawList::AddText() calls ImBitmapFont::RenderText()
4168 void ImGui::RenderText(ImVec2 pos, const char* text, const char* text_end, bool hide_text_after_hash)
4169 {
4170  ImGuiContext& g = *GImGui;
4171  ImGuiWindow* window = g.CurrentWindow;
4172 
4173  // Hide anything after a '##' string
4174  const char* text_display_end;
4175  if (hide_text_after_hash)
4176  {
4177  text_display_end = FindRenderedTextEnd(text, text_end);
4178  }
4179  else
4180  {
4181  if (!text_end)
4182  text_end = text + strlen(text); // FIXME-OPT
4183  text_display_end = text_end;
4184  }
4185 
4186  const int text_len = (int)(text_display_end - text);
4187  if (text_len > 0)
4188  {
4189  window->DrawList->AddText(g.Font, g.FontSize, pos, GetColorU32(ImGuiCol_Text), text, text_display_end);
4190  if (g.LogEnabled)
4191  LogRenderedText(&pos, text, text_display_end);
4192  }
4193 }
4194 
4195 void ImGui::RenderTextWrapped(ImVec2 pos, const char* text, const char* text_end, float wrap_width)
4196 {
4197  ImGuiContext& g = *GImGui;
4198  ImGuiWindow* window = g.CurrentWindow;
4199 
4200  if (!text_end)
4201  text_end = text + strlen(text); // FIXME-OPT
4202 
4203  const int text_len = (int)(text_end - text);
4204  if (text_len > 0)
4205  {
4206  window->DrawList->AddText(g.Font, g.FontSize, pos, GetColorU32(ImGuiCol_Text), text, text_end, wrap_width);
4207  if (g.LogEnabled)
4208  LogRenderedText(&pos, text, text_end);
4209  }
4210 }
4211 
4212 // Default clip_rect uses (pos_min,pos_max)
4213 // Handle clipping on CPU immediately (vs typically let the GPU clip the triangles that are overlapping the clipping rectangle edges)
4214 void ImGui::RenderTextClipped(const ImVec2& pos_min, const ImVec2& pos_max, const char* text, const char* text_end, const ImVec2* text_size_if_known, const ImVec2& align, const ImRect* clip_rect)
4215 {
4216  // Hide anything after a '##' string
4217  const char* text_display_end = FindRenderedTextEnd(text, text_end);
4218  const int text_len = (int)(text_display_end - text);
4219  if (text_len == 0)
4220  return;
4221 
4222  ImGuiContext& g = *GImGui;
4223  ImGuiWindow* window = g.CurrentWindow;
4224 
4225  // Perform CPU side clipping for single clipped element to avoid using scissor state
4226  ImVec2 pos = pos_min;
4227  const ImVec2 text_size = text_size_if_known ? *text_size_if_known : CalcTextSize(text, text_display_end, false, 0.0f);
4228 
4229  const ImVec2* clip_min = clip_rect ? &clip_rect->Min : &pos_min;
4230  const ImVec2* clip_max = clip_rect ? &clip_rect->Max : &pos_max;
4231  bool need_clipping = (pos.x + text_size.x >= clip_max->x) || (pos.y + text_size.y >= clip_max->y);
4232  if (clip_rect) // If we had no explicit clipping rectangle then pos==clip_min
4233  need_clipping |= (pos.x < clip_min->x) || (pos.y < clip_min->y);
4234 
4235  // Align whole block. We should defer that to the better rendering function when we'll have support for individual line alignment.
4236  if (align.x > 0.0f) pos.x = ImMax(pos.x, pos.x + (pos_max.x - pos.x - text_size.x) * align.x);
4237  if (align.y > 0.0f) pos.y = ImMax(pos.y, pos.y + (pos_max.y - pos.y - text_size.y) * align.y);
4238 
4239  // Render
4240  if (need_clipping)
4241  {
4242  ImVec4 fine_clip_rect(clip_min->x, clip_min->y, clip_max->x, clip_max->y);
4243  window->DrawList->AddText(g.Font, g.FontSize, pos, GetColorU32(ImGuiCol_Text), text, text_display_end, 0.0f, &fine_clip_rect);
4244  }
4245  else
4246  {
4247  window->DrawList->AddText(g.Font, g.FontSize, pos, GetColorU32(ImGuiCol_Text), text, text_display_end, 0.0f, NULL);
4248  }
4249  if (g.LogEnabled)
4250  LogRenderedText(&pos, text, text_display_end);
4251 }
4252 
4253 // Render a rectangle shaped with optional rounding and borders
4254 void ImGui::RenderFrame(ImVec2 p_min, ImVec2 p_max, ImU32 fill_col, bool border, float rounding)
4255 {
4256  ImGuiContext& g = *GImGui;
4257  ImGuiWindow* window = g.CurrentWindow;
4258  window->DrawList->AddRectFilled(p_min, p_max, fill_col, rounding);
4259  const float border_size = g.Style.FrameBorderSize;
4260  if (border && border_size > 0.0f)
4261  {
4262  window->DrawList->AddRect(p_min+ImVec2(1,1), p_max+ImVec2(1,1), GetColorU32(ImGuiCol_BorderShadow), rounding, ImDrawCornerFlags_All, border_size);
4263  window->DrawList->AddRect(p_min, p_max, GetColorU32(ImGuiCol_Border), rounding, ImDrawCornerFlags_All, border_size);
4264  }
4265 }
4266 
4267 void ImGui::RenderFrameBorder(ImVec2 p_min, ImVec2 p_max, float rounding)
4268 {
4269  ImGuiContext& g = *GImGui;
4270  ImGuiWindow* window = g.CurrentWindow;
4271  const float border_size = g.Style.FrameBorderSize;
4272  if (border_size > 0.0f)
4273  {
4274  window->DrawList->AddRect(p_min+ImVec2(1,1), p_max+ImVec2(1,1), GetColorU32(ImGuiCol_BorderShadow), rounding, ImDrawCornerFlags_All, border_size);
4275  window->DrawList->AddRect(p_min, p_max, GetColorU32(ImGuiCol_Border), rounding, ImDrawCornerFlags_All, border_size);
4276  }
4277 }
4278 
4279 // Render a triangle to denote expanded/collapsed state
4281 {
4282  ImGuiContext& g = *GImGui;
4283  ImGuiWindow* window = g.CurrentWindow;
4284 
4285  const float h = g.FontSize * 1.00f;
4286  float r = h * 0.40f * scale;
4287  ImVec2 center = p_min + ImVec2(h * 0.50f, h * 0.50f * scale);
4288 
4289  ImVec2 a, b, c;
4290  switch (dir)
4291  {
4292  case ImGuiDir_Up:
4293  case ImGuiDir_Down:
4294  if (dir == ImGuiDir_Up) r = -r;
4295  center.y -= r * 0.25f;
4296  a = ImVec2(0,1) * r;
4297  b = ImVec2(-0.866f,-0.5f) * r;
4298  c = ImVec2(+0.866f,-0.5f) * r;
4299  break;
4300  case ImGuiDir_Left:
4301  case ImGuiDir_Right:
4302  if (dir == ImGuiDir_Left) r = -r;
4303  center.x -= r * 0.25f;
4304  a = ImVec2(1,0) * r;
4305  b = ImVec2(-0.500f,+0.866f) * r;
4306  c = ImVec2(-0.500f,-0.866f) * r;
4307  break;
4308  case ImGuiDir_None:
4309  case ImGuiDir_Count_:
4310  IM_ASSERT(0);
4311  break;
4312  }
4313 
4314  window->DrawList->AddTriangleFilled(center + a, center + b, center + c, GetColorU32(ImGuiCol_Text));
4315 }
4316 
4318 {
4319  ImGuiContext& g = *GImGui;
4320  ImGuiWindow* window = g.CurrentWindow;
4321  window->DrawList->AddCircleFilled(pos, GImGui->FontSize*0.20f, GetColorU32(ImGuiCol_Text), 8);
4322 }
4323 
4324 void ImGui::RenderCheckMark(ImVec2 pos, ImU32 col, float sz)
4325 {
4326  ImGuiContext& g = *GImGui;
4327  ImGuiWindow* window = g.CurrentWindow;
4328 
4329  float thickness = ImMax(sz / 5.0f, 1.0f);
4330  sz -= thickness*0.5f;
4331  pos += ImVec2(thickness*0.25f, thickness*0.25f);
4332 
4333  float third = sz / 3.0f;
4334  float bx = pos.x + third;
4335  float by = pos.y + sz - third*0.5f;
4336  window->DrawList->PathLineTo(ImVec2(bx - third, by - third));
4337  window->DrawList->PathLineTo(ImVec2(bx, by));
4338  window->DrawList->PathLineTo(ImVec2(bx + third*2, by - third*2));
4339  window->DrawList->PathStroke(col, false, thickness);
4340 }
4341 
4343 {
4344  ImGuiContext& g = *GImGui;
4345  if (id != g.NavId)
4346  return;
4347  if (g.NavDisableHighlight && !(flags & ImGuiNavHighlightFlags_AlwaysDraw))
4348  return;
4350  if (window->DC.NavHideHighlightOneFrame)
4351  return;
4352 
4353  float rounding = (flags & ImGuiNavHighlightFlags_NoRounding) ? 0.0f : g.Style.FrameRounding;
4354  ImRect display_rect = bb;
4355  display_rect.ClipWith(window->ClipRect);
4357  {
4358  const float THICKNESS = 2.0f;
4359  const float DISTANCE = 3.0f + THICKNESS * 0.5f;
4360  display_rect.Expand(ImVec2(DISTANCE,DISTANCE));
4361  bool fully_visible = window->ClipRect.Contains(display_rect);
4362  if (!fully_visible)
4363  window->DrawList->PushClipRect(display_rect.Min, display_rect.Max);
4364  window->DrawList->AddRect(display_rect.Min + ImVec2(THICKNESS*0.5f,THICKNESS*0.5f), display_rect.Max - ImVec2(THICKNESS*0.5f,THICKNESS*0.5f), GetColorU32(ImGuiCol_NavHighlight), rounding, ImDrawCornerFlags_All, THICKNESS);
4365  if (!fully_visible)
4366  window->DrawList->PopClipRect();
4367  }
4369  {
4370  window->DrawList->AddRect(display_rect.Min, display_rect.Max, GetColorU32(ImGuiCol_NavHighlight), rounding, ~0, 1.0f);
4371  }
4372 }
4373 
4374 // Calculate text size. Text can be multi-line. Optionally ignore text after a ## marker.
4375 // CalcTextSize("") should return ImVec2(0.0f, GImGui->FontSize)
4376 ImVec2 ImGui::CalcTextSize(const char* text, const char* text_end, bool hide_text_after_double_hash, float wrap_width)
4377 {
4378  ImGuiContext& g = *GImGui;
4379 
4380  const char* text_display_end;
4381  if (hide_text_after_double_hash)
4382  text_display_end = FindRenderedTextEnd(text, text_end); // Hide anything after a '##' string
4383  else
4384  text_display_end = text_end;
4385 
4386  ImFont* font = g.Font;
4387  const float font_size = g.FontSize;
4388  if (text == text_display_end)
4389  return ImVec2(0.0f, font_size);
4390  ImVec2 text_size = font->CalcTextSizeA(font_size, FLT_MAX, wrap_width, text, text_display_end, NULL);
4391 
4392  // Cancel out character spacing for the last character of a line (it is baked into glyph->AdvanceX field)
4393  const float font_scale = font_size / font->FontSize;
4394  const float character_spacing_x = 1.0f * font_scale;
4395  if (text_size.x > 0.0f)
4396  text_size.x -= character_spacing_x;
4397  text_size.x = (float)(int)(text_size.x + 0.95f);
4398 
4399  return text_size;
4400 }
4401 
4402 // Helper to calculate coarse clipping of large list of evenly sized items.
4403 // NB: Prefer using the ImGuiListClipper higher-level helper if you can! Read comments and instructions there on how those use this sort of pattern.
4404 // NB: 'items_count' is only used to clamp the result, if you don't know your count you can use INT_MAX
4405 void ImGui::CalcListClipping(int items_count, float items_height, int* out_items_display_start, int* out_items_display_end)
4406 {
4407  ImGuiContext& g = *GImGui;
4408  ImGuiWindow* window = g.CurrentWindow;
4409  if (g.LogEnabled)
4410  {
4411  // If logging is active, do not perform any clipping
4412  *out_items_display_start = 0;
4413  *out_items_display_end = items_count;
4414  return;
4415  }
4416  if (window->SkipItems)
4417  {
4418  *out_items_display_start = *out_items_display_end = 0;
4419  return;
4420  }
4421 
4422  const ImVec2 pos = window->DC.CursorPos;
4423  int start = (int)((window->ClipRect.Min.y - pos.y) / items_height);
4424  int end = (int)((window->ClipRect.Max.y - pos.y) / items_height);
4425  if (g.NavMoveRequest && g.NavMoveDir == ImGuiDir_Up) // When performing a navigation request, ensure we have one item extra in the direction we are moving to
4426  start--;
4427  if (g.NavMoveRequest && g.NavMoveDir == ImGuiDir_Down)
4428  end++;
4429 
4430  start = ImClamp(start, 0, items_count);
4431  end = ImClamp(end + 1, start, items_count);
4432  *out_items_display_start = start;
4433  *out_items_display_end = end;
4434 }
4435 
4436 // Find window given position, search front-to-back
4437 // FIXME: Note that we have a lag here because WindowRectClipped is updated in Begin() so windows moved by user via SetWindowPos() and not SetNextWindowPos() will have that rectangle lagging by a frame at the time FindHoveredWindow() is called, aka before the next Begin(). Moving window thankfully isn't affected.
4439 {
4440  ImGuiContext& g = *GImGui;
4441  for (int i = g.Windows.Size - 1; i >= 0; i--)
4442  {
4443  ImGuiWindow* window = g.Windows[i];
4444  if (!window->Active)
4445  continue;
4446  if (window->Flags & ImGuiWindowFlags_NoInputs)
4447  continue;
4448 
4449  // Using the clipped AABB, a child window will typically be clipped by its parent (not always)
4450  ImRect bb(window->WindowRectClipped.Min - g.Style.TouchExtraPadding, window->WindowRectClipped.Max + g.Style.TouchExtraPadding);
4451  if (bb.Contains(g.IO.MousePos))
4452  return window;
4453  }
4454  return NULL;
4455 }
4456 
4457 // Test if mouse cursor is hovering given rectangle
4458 // NB- Rectangle is clipped by our current clip setting
4459 // NB- Expand the rectangle to be generous on imprecise inputs systems (g.Style.TouchExtraPadding)
4460 bool ImGui::IsMouseHoveringRect(const ImVec2& r_min, const ImVec2& r_max, bool clip)
4461 {
4462  ImGuiContext& g = *GImGui;
4463  ImGuiWindow* window = g.CurrentWindow;
4464 
4465  // Clip
4466  ImRect rect_clipped(r_min, r_max);
4467  if (clip)
4468  rect_clipped.ClipWith(window->ClipRect);
4469 
4470  // Expand for touch input
4471  const ImRect rect_for_touch(rect_clipped.Min - g.Style.TouchExtraPadding, rect_clipped.Max + g.Style.TouchExtraPadding);
4472  return rect_for_touch.Contains(g.IO.MousePos);
4473 }
4474 
4475 static bool IsKeyPressedMap(ImGuiKey key, bool repeat)
4476 {
4477  const int key_index = GImGui->IO.KeyMap[key];
4478  return (key_index >= 0) ? ImGui::IsKeyPressed(key_index, repeat) : false;
4479 }
4480 
4482 {
4483  IM_ASSERT(imgui_key >= 0 && imgui_key < ImGuiKey_COUNT);
4484  return GImGui->IO.KeyMap[imgui_key];
4485 }
4486 
4487 // Note that imgui doesn't know the semantic of each entry of io.KeyDown[]. Use your own indices/enums according to how your back-end/engine stored them into KeyDown[]!
4488 bool ImGui::IsKeyDown(int user_key_index)
4489 {
4490  if (user_key_index < 0) return false;
4491  IM_ASSERT(user_key_index >= 0 && user_key_index < IM_ARRAYSIZE(GImGui->IO.KeysDown));
4492  return GImGui->IO.KeysDown[user_key_index];
4493 }
4494 
4495 int ImGui::CalcTypematicPressedRepeatAmount(float t, float t_prev, float repeat_delay, float repeat_rate)
4496 {
4497  if (t == 0.0f)
4498  return 1;
4499  if (t <= repeat_delay || repeat_rate <= 0.0f)
4500  return 0;
4501  const int count = (int)((t - repeat_delay) / repeat_rate) - (int)((t_prev - repeat_delay) / repeat_rate);
4502  return (count > 0) ? count : 0;
4503 }
4504 
4505 int ImGui::GetKeyPressedAmount(int key_index, float repeat_delay, float repeat_rate)
4506 {
4507  ImGuiContext& g = *GImGui;
4508  if (key_index < 0) return false;
4509  IM_ASSERT(key_index >= 0 && key_index < IM_ARRAYSIZE(g.IO.KeysDown));
4510  const float t = g.IO.KeysDownDuration[key_index];
4511  return CalcTypematicPressedRepeatAmount(t, t - g.IO.DeltaTime, repeat_delay, repeat_rate);
4512 }
4513 
4514 bool ImGui::IsKeyPressed(int user_key_index, bool repeat)
4515 {
4516  ImGuiContext& g = *GImGui;
4517  if (user_key_index < 0) return false;
4518  IM_ASSERT(user_key_index >= 0 && user_key_index < IM_ARRAYSIZE(g.IO.KeysDown));
4519  const float t = g.IO.KeysDownDuration[user_key_index];
4520  if (t == 0.0f)
4521  return true;
4522  if (repeat && t > g.IO.KeyRepeatDelay)
4523  return GetKeyPressedAmount(user_key_index, g.IO.KeyRepeatDelay, g.IO.KeyRepeatRate) > 0;
4524  return false;
4525 }
4526 
4527 bool ImGui::IsKeyReleased(int user_key_index)
4528 {
4529  ImGuiContext& g = *GImGui;
4530  if (user_key_index < 0) return false;
4531  IM_ASSERT(user_key_index >= 0 && user_key_index < IM_ARRAYSIZE(g.IO.KeysDown));
4532  return g.IO.KeysDownDurationPrev[user_key_index] >= 0.0f && !g.IO.KeysDown[user_key_index];
4533 }
4534 
4535 bool ImGui::IsMouseDown(int button)
4536 {
4537  ImGuiContext& g = *GImGui;
4538  IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown));
4539  return g.IO.MouseDown[button];
4540 }
4541 
4543 {
4544  ImGuiContext& g = *GImGui;
4545  for (int n = 0; n < IM_ARRAYSIZE(g.IO.MouseDown); n++)
4546  if (g.IO.MouseDown[n])
4547  return true;
4548  return false;
4549 }
4550 
4551 bool ImGui::IsMouseClicked(int button, bool repeat)
4552 {
4553  ImGuiContext& g = *GImGui;
4554  IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown));
4555  const float t = g.IO.MouseDownDuration[button];
4556  if (t == 0.0f)
4557  return true;
4558 
4559  if (repeat && t > g.IO.KeyRepeatDelay)
4560  {
4561  float delay = g.IO.KeyRepeatDelay, rate = g.IO.KeyRepeatRate;
4562  if ((fmodf(t - delay, rate) > rate*0.5f) != (fmodf(t - delay - g.IO.DeltaTime, rate) > rate*0.5f))
4563  return true;
4564  }
4565 
4566  return false;
4567 }
4568 
4569 bool ImGui::IsMouseReleased(int button)
4570 {
4571  ImGuiContext& g = *GImGui;
4572  IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown));
4573  return g.IO.MouseReleased[button];
4574 }
4575 
4577 {
4578  ImGuiContext& g = *GImGui;
4579  IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown));
4580  return g.IO.MouseDoubleClicked[button];
4581 }
4582 
4583 bool ImGui::IsMouseDragging(int button, float lock_threshold)
4584 {
4585  ImGuiContext& g = *GImGui;
4586  IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown));
4587  if (!g.IO.MouseDown[button])
4588  return false;
4589  if (lock_threshold < 0.0f)
4590  lock_threshold = g.IO.MouseDragThreshold;
4591  return g.IO.MouseDragMaxDistanceSqr[button] >= lock_threshold * lock_threshold;
4592 }
4593 
4595 {
4596  return GImGui->IO.MousePos;
4597 }
4598 
4599 // NB: prefer to call right after BeginPopup(). At the time Selectable/MenuItem is activated, the popup is already closed!
4601 {
4602  ImGuiContext& g = *GImGui;
4603  if (g.CurrentPopupStack.Size > 0)
4604  return g.OpenPopupStack[g.CurrentPopupStack.Size-1].OpenMousePos;
4605  return g.IO.MousePos;
4606 }
4607 
4608 // We typically use ImVec2(-FLT_MAX,-FLT_MAX) to denote an invalid mouse position
4609 bool ImGui::IsMousePosValid(const ImVec2* mouse_pos)
4610 {
4611  if (mouse_pos == NULL)
4612  mouse_pos = &GImGui->IO.MousePos;
4613  const float MOUSE_INVALID = -256000.0f;
4614  return mouse_pos->x >= MOUSE_INVALID && mouse_pos->y >= MOUSE_INVALID;
4615 }
4616 
4617 // NB: This is only valid if IsMousePosValid(). Back-ends in theory should always keep mouse position valid when dragging even outside the client window.
4618 ImVec2 ImGui::GetMouseDragDelta(int button, float lock_threshold)
4619 {
4620  ImGuiContext& g = *GImGui;
4621  IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown));
4622  if (lock_threshold < 0.0f)
4623  lock_threshold = g.IO.MouseDragThreshold;
4624  if (g.IO.MouseDown[button])
4625  if (g.IO.MouseDragMaxDistanceSqr[button] >= lock_threshold * lock_threshold)
4626  return g.IO.MousePos - g.IO.MouseClickedPos[button]; // Assume we can only get active with left-mouse button (at the moment).
4627  return ImVec2(0.0f, 0.0f);
4628 }
4629 
4631 {
4632  ImGuiContext& g = *GImGui;
4633  IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown));
4634  // NB: We don't need to reset g.IO.MouseDragMaxDistanceSqr
4635  g.IO.MouseClickedPos[button] = g.IO.MousePos;
4636 }
4637 
4639 {
4640  return GImGui->MouseCursor;
4641 }
4642 
4644 {
4645  GImGui->MouseCursor = cursor_type;
4646 }
4647 
4649 {
4650  GImGui->WantCaptureKeyboardNextFrame = capture ? 1 : 0;
4651 }
4652 
4653 void ImGui::CaptureMouseFromApp(bool capture)
4654 {
4655  GImGui->WantCaptureMouseNextFrame = capture ? 1 : 0;
4656 }
4657 
4659 {
4660  ImGuiContext& g = *GImGui;
4661  if (g.ActiveId)
4662  {
4663  ImGuiWindow* window = g.CurrentWindow;
4664  return g.ActiveId == window->DC.LastItemId;
4665  }
4666  return false;
4667 }
4668 
4670 {
4671  ImGuiContext& g = *GImGui;
4672  return g.NavId && !g.NavDisableHighlight && g.NavId == g.CurrentWindow->DC.LastItemId;
4673 }
4674 
4675 bool ImGui::IsItemClicked(int mouse_button)
4676 {
4677  return IsMouseClicked(mouse_button) && IsItemHovered(ImGuiHoveredFlags_Default);
4678 }
4679 
4681 {
4682  ImGuiContext& g = *GImGui;
4683  return g.HoveredId != 0 || g.HoveredIdPreviousFrame != 0;
4684 }
4685 
4687 {
4688  ImGuiContext& g = *GImGui;
4689  return g.ActiveId != 0;
4690 }
4691 
4693 {
4694  ImGuiContext& g = *GImGui;
4695  return g.NavId != 0 && !g.NavDisableHighlight;
4696 }
4697 
4699 {
4700  ImGuiWindow* window = GetCurrentWindowRead();
4701  return window->ClipRect.Overlaps(window->DC.LastItemRect);
4702 }
4703 
4704 // Allow last item to be overlapped by a subsequent item. Both may be activated during the same frame before the later one takes priority.
4706 {
4707  ImGuiContext& g = *GImGui;
4708  if (g.HoveredId == g.CurrentWindow->DC.LastItemId)
4709  g.HoveredIdAllowOverlap = true;
4710  if (g.ActiveId == g.CurrentWindow->DC.LastItemId)
4711  g.ActiveIdAllowOverlap = true;
4712 }
4713 
4715 {
4716  ImGuiWindow* window = GetCurrentWindowRead();
4717  return window->DC.LastItemRect.Min;
4718 }
4719 
4721 {
4722  ImGuiWindow* window = GetCurrentWindowRead();
4723  return window->DC.LastItemRect.Max;
4724 }
4725 
4727 {
4728  ImGuiWindow* window = GetCurrentWindowRead();
4729  return window->DC.LastItemRect.GetSize();
4730 }
4731 
4733 {
4734  ImGuiContext& g = *GImGui;
4735  if (g.IO.DisplayVisibleMin.x != g.IO.DisplayVisibleMax.x && g.IO.DisplayVisibleMin.y != g.IO.DisplayVisibleMax.y)
4736  return ImRect(g.IO.DisplayVisibleMin, g.IO.DisplayVisibleMax);
4737  return ImRect(0.0f, 0.0f, g.IO.DisplaySize.x, g.IO.DisplaySize.y);
4738 }
4739 
4740 // Not exposed publicly as BeginTooltip() because bool parameters are evil. Let's see if other needs arise first.
4741 void ImGui::BeginTooltipEx(ImGuiWindowFlags extra_flags, bool override_previous_tooltip)
4742 {
4743  ImGuiContext& g = *GImGui;
4744  char window_name[16];
4745  ImFormatString(window_name, IM_ARRAYSIZE(window_name), "##Tooltip_%02d", g.TooltipOverrideCount);
4746  if (override_previous_tooltip)
4747  if (ImGuiWindow* window = FindWindowByName(window_name))
4748  if (window->Active)
4749  {
4750  // Hide previous tooltips. We can't easily "reset" the content of a window so we create a new one.
4751  window->HiddenFrames = 1;
4752  ImFormatString(window_name, IM_ARRAYSIZE(window_name), "##Tooltip_%02d", ++g.TooltipOverrideCount);
4753  }
4755  Begin(window_name, NULL, flags | extra_flags);
4756 }
4757 
4758 void ImGui::SetTooltipV(const char* fmt, va_list args)
4759 {
4760  BeginTooltipEx(0, true);
4761  TextV(fmt, args);
4762  EndTooltip();
4763 }
4764 
4765 void ImGui::SetTooltip(const char* fmt, ...)
4766 {
4767  va_list args;
4768  va_start(args, fmt);
4769  SetTooltipV(fmt, args);
4770  va_end(args);
4771 }
4772 
4774 {
4775  BeginTooltipEx(0, false);
4776 }
4777 
4779 {
4780  IM_ASSERT(GetCurrentWindowRead()->Flags & ImGuiWindowFlags_Tooltip); // Mismatched BeginTooltip()/EndTooltip() calls
4781  End();
4782 }
4783 
4784 // Mark popup as open (toggle toward open state).
4785 // Popups are closed when user click outside, or activate a pressable item, or CloseCurrentPopup() is called within a BeginPopup()/EndPopup() block.
4786 // Popup identifiers are relative to the current ID-stack (so OpenPopup and BeginPopup needs to be at the same level).
4787 // One open popup per level of the popup hierarchy (NB: when assigning we reset the Window member of ImGuiPopupRef to NULL)
4789 {
4790  ImGuiContext& g = *GImGui;
4791  ImGuiWindow* parent_window = g.CurrentWindow;
4792  int current_stack_size = g.CurrentPopupStack.Size;
4793  ImGuiPopupRef popup_ref; // Tagged as new ref as Window will be set back to NULL if we write this into OpenPopupStack.
4794  popup_ref.PopupId = id;
4795  popup_ref.Window = NULL;
4796  popup_ref.ParentWindow = parent_window;
4797  popup_ref.OpenFrameCount = g.FrameCount;
4798  popup_ref.OpenParentId = parent_window->IDStack.back();
4799  popup_ref.OpenMousePos = g.IO.MousePos;
4800  popup_ref.OpenPopupPos = (!g.NavDisableHighlight && g.NavDisableMouseHover) ? NavCalcPreferredMousePos() : g.IO.MousePos;
4801 
4802  if (g.OpenPopupStack.Size < current_stack_size + 1)
4803  {
4804  g.OpenPopupStack.push_back(popup_ref);
4805  }
4806  else
4807  {
4808  // Close child popups if any
4809  g.OpenPopupStack.resize(current_stack_size + 1);
4810 
4811  // Gently handle the user mistakenly calling OpenPopup() every frame. It is a programming mistake! However, if we were to run the regular code path, the ui
4812  // would become completely unusable because the popup will always be in hidden-while-calculating-size state _while_ claiming focus. Which would be a very confusing
4813  // situation for the programmer. Instead, we silently allow the popup to proceed, it will keep reappearing and the programming error will be more obvious to understand.
4814  if (g.OpenPopupStack[current_stack_size].PopupId == id && g.OpenPopupStack[current_stack_size].OpenFrameCount == g.FrameCount - 1)
4815  g.OpenPopupStack[current_stack_size].OpenFrameCount = popup_ref.OpenFrameCount;
4816  else
4817  g.OpenPopupStack[current_stack_size] = popup_ref;
4818 
4819  // When reopening a popup we first refocus its parent, otherwise if its parent is itself a popup it would get closed by ClosePopupsOverWindow().
4820  // This is equivalent to what ClosePopupToLevel() does.
4821  //if (g.OpenPopupStack[current_stack_size].PopupId == id)
4822  // FocusWindow(parent_window);
4823  }
4824 }
4825 
4826 void ImGui::OpenPopup(const char* str_id)
4827 {
4828  ImGuiContext& g = *GImGui;
4829  OpenPopupEx(g.CurrentWindow->GetID(str_id));
4830 }
4831 
4833 {
4834  ImGuiContext& g = *GImGui;
4835  if (g.OpenPopupStack.empty())
4836  return;
4837 
4838  // When popups are stacked, clicking on a lower level popups puts focus back to it and close popups above it.
4839  // Don't close our own child popup windows.
4840  int n = 0;
4841  if (ref_window)
4842  {
4843  for (n = 0; n < g.OpenPopupStack.Size; n++)
4844  {
4845  ImGuiPopupRef& popup = g.OpenPopupStack[n];
4846  if (!popup.Window)
4847  continue;
4848  IM_ASSERT((popup.Window->Flags & ImGuiWindowFlags_Popup) != 0);
4850  continue;
4851 
4852  // Trim the stack if popups are not direct descendant of the reference window (which is often the NavWindow)
4853  bool has_focus = false;
4854  for (int m = n; m < g.OpenPopupStack.Size && !has_focus; m++)
4855  has_focus = (g.OpenPopupStack[m].Window && g.OpenPopupStack[m].Window->RootWindow == ref_window->RootWindow);
4856  if (!has_focus)
4857  break;
4858  }
4859  }
4860  if (n < g.OpenPopupStack.Size) // This test is not required but it allows to set a convenient breakpoint on the block below
4862 }
4863 
4865 {
4866  ImGuiContext& g = *GImGui;
4867  for (int n = g.OpenPopupStack.Size-1; n >= 0; n--)
4868  if (ImGuiWindow* popup = g.OpenPopupStack.Data[n].Window)
4869  if (popup->Flags & ImGuiWindowFlags_Modal)
4870  return popup;
4871  return NULL;
4872 }
4873 
4874 static void ClosePopupToLevel(int remaining)
4875 {
4876  IM_ASSERT(remaining >= 0);
4877  ImGuiContext& g = *GImGui;
4878  ImGuiWindow* focus_window = (remaining > 0) ? g.OpenPopupStack[remaining-1].Window : g.OpenPopupStack[0].ParentWindow;
4879  if (g.NavLayer == 0)
4880  focus_window = NavRestoreLastChildNavWindow(focus_window);
4881  ImGui::FocusWindow(focus_window);
4882  focus_window->DC.NavHideHighlightOneFrame = true;
4883  g.OpenPopupStack.resize(remaining);
4884 }
4885 
4887 {
4888  if (!IsPopupOpen(id))
4889  return;
4890  ImGuiContext& g = *GImGui;
4891  ClosePopupToLevel(g.OpenPopupStack.Size - 1);
4892 }
4893 
4894 // Close the popup we have begin-ed into.
4896 {
4897  ImGuiContext& g = *GImGui;
4898  int popup_idx = g.CurrentPopupStack.Size - 1;
4899  if (popup_idx < 0 || popup_idx >= g.OpenPopupStack.Size || g.CurrentPopupStack[popup_idx].PopupId != g.OpenPopupStack[popup_idx].PopupId)
4900  return;
4901  while (popup_idx > 0 && g.OpenPopupStack[popup_idx].Window && (g.OpenPopupStack[popup_idx].Window->Flags & ImGuiWindowFlags_ChildMenu))
4902  popup_idx--;
4903  ClosePopupToLevel(popup_idx);
4904 }
4905 
4907 {
4908  ImGuiContext& g = *GImGui;
4909  if (!IsPopupOpen(id))
4910  {
4911  g.NextWindowData.Clear(); // We behave like Begin() and need to consume those values
4912  return false;
4913  }
4914 
4915  char name[20];
4916  if (extra_flags & ImGuiWindowFlags_ChildMenu)
4917  ImFormatString(name, IM_ARRAYSIZE(name), "##Menu_%02d", g.CurrentPopupStack.Size); // Recycle windows based on depth
4918  else
4919  ImFormatString(name, IM_ARRAYSIZE(name), "##Popup_%08x", id); // Not recycling, so we can close/open during the same frame
4920 
4921  bool is_open = Begin(name, NULL, extra_flags | ImGuiWindowFlags_Popup);
4922  if (!is_open) // NB: Begin can return false when the popup is completely clipped (e.g. zero size display)
4923  EndPopup();
4924 
4925  return is_open;
4926 }
4927 
4928 bool ImGui::BeginPopup(const char* str_id, ImGuiWindowFlags flags)
4929 {
4930  ImGuiContext& g = *GImGui;
4931  if (g.OpenPopupStack.Size <= g.CurrentPopupStack.Size) // Early out for performance
4932  {
4933  g.NextWindowData.Clear(); // We behave like Begin() and need to consume those values
4934  return false;
4935  }
4937 }
4938 
4940 {
4941  ImGuiContext& g = *GImGui;
4942  return g.OpenPopupStack.Size > g.CurrentPopupStack.Size && g.OpenPopupStack[g.CurrentPopupStack.Size].PopupId == id;
4943 }
4944 
4945 bool ImGui::IsPopupOpen(const char* str_id)
4946 {
4947  ImGuiContext& g = *GImGui;
4948  return g.OpenPopupStack.Size > g.CurrentPopupStack.Size && g.OpenPopupStack[g.CurrentPopupStack.Size].PopupId == g.CurrentWindow->GetID(str_id);
4949 }
4950 
4951 bool ImGui::BeginPopupModal(const char* name, bool* p_open, ImGuiWindowFlags flags)
4952 {
4953  ImGuiContext& g = *GImGui;
4954  ImGuiWindow* window = g.CurrentWindow;
4955  const ImGuiID id = window->GetID(name);
4956  if (!IsPopupOpen(id))
4957  {
4958  g.NextWindowData.Clear(); // We behave like Begin() and need to consume those values
4959  return false;
4960  }
4961 
4962  // Center modal windows by default
4963  // FIXME: Should test for (PosCond & window->SetWindowPosAllowFlags) with the upcoming window.
4964  if (g.NextWindowData.PosCond == 0)
4965  SetNextWindowPos(g.IO.DisplaySize * 0.5f, ImGuiCond_Appearing, ImVec2(0.5f, 0.5f));
4966 
4968  if (!is_open || (p_open && !*p_open)) // NB: is_open can be 'false' when the popup is completely clipped (e.g. zero size display)
4969  {
4970  EndPopup();
4971  if (is_open)
4972  ClosePopup(id);
4973  return false;
4974  }
4975 
4976  return is_open;
4977 }
4978 
4980 {
4981  ImGuiContext& g = *GImGui;
4982  if (g.NavWindow == window && NavMoveRequestButNoResultYet())
4983  if ((g.NavMoveDir == ImGuiDir_Up || g.NavMoveDir == ImGuiDir_Down) && g.NavMoveRequestForward == ImGuiNavForward_None && g.NavLayer == 0)
4984  {
4987  g.NavWindow->NavRectRel[0].Min.y = g.NavWindow->NavRectRel[0].Max.y = ((g.NavMoveDir == ImGuiDir_Up) ? ImMax(window->SizeFull.y, window->SizeContents.y) : 0.0f) - window->Scroll.y;
4988  }
4989 }
4990 
4992 {
4993  ImGuiContext& g = *GImGui; (void)g;
4994  IM_ASSERT(g.CurrentWindow->Flags & ImGuiWindowFlags_Popup); // Mismatched BeginPopup()/EndPopup() calls
4995  IM_ASSERT(g.CurrentPopupStack.Size > 0);
4996 
4997  // Make all menus and popups wrap around for now, may need to expose that policy.
4998  NavProcessMoveRequestWrapAround(g.CurrentWindow);
4999 
5000  End();
5001 }
5002 
5003 bool ImGui::OpenPopupOnItemClick(const char* str_id, int mouse_button)
5004 {
5005  ImGuiWindow* window = GImGui->CurrentWindow;
5007  {
5008  ImGuiID id = str_id ? window->GetID(str_id) : window->DC.LastItemId; // If user hasn't passed an ID, we can use the LastItemID. Using LastItemID as a Popup ID won't conflict!
5009  IM_ASSERT(id != 0); // However, you cannot pass a NULL str_id if the last item has no identifier (e.g. a Text() item)
5010  OpenPopupEx(id);
5011  return true;
5012  }
5013  return false;
5014 }
5015 
5016 // This is a helper to handle the simplest case of associating one named popup to one given widget.
5017 // You may want to handle this on user side if you have specific needs (e.g. tweaking IsItemHovered() parameters).
5018 // You can pass a NULL str_id to use the identifier of the last item.
5019 bool ImGui::BeginPopupContextItem(const char* str_id, int mouse_button)
5020 {
5021  ImGuiWindow* window = GImGui->CurrentWindow;
5022  ImGuiID id = str_id ? window->GetID(str_id) : window->DC.LastItemId; // If user hasn't passed an ID, we can use the LastItemID. Using LastItemID as a Popup ID won't conflict!
5023  IM_ASSERT(id != 0); // However, you cannot pass a NULL str_id if the last item has no identifier (e.g. a Text() item)
5025  OpenPopupEx(id);
5027 }
5028 
5029 bool ImGui::BeginPopupContextWindow(const char* str_id, int mouse_button, bool also_over_items)
5030 {
5031  if (!str_id)
5032  str_id = "window_context";
5033  ImGuiID id = GImGui->CurrentWindow->GetID(str_id);
5035  if (also_over_items || !IsAnyItemHovered())
5036  OpenPopupEx(id);
5038 }
5039 
5040 bool ImGui::BeginPopupContextVoid(const char* str_id, int mouse_button)
5041 {
5042  if (!str_id)
5043  str_id = "void_context";
5044  ImGuiID id = GImGui->CurrentWindow->GetID(str_id);
5046  OpenPopupEx(id);
5048 }
5049 
5050 static bool BeginChildEx(const char* name, ImGuiID id, const ImVec2& size_arg, bool border, ImGuiWindowFlags extra_flags)
5051 {
5052  ImGuiContext& g = *GImGui;
5053  ImGuiWindow* parent_window = ImGui::GetCurrentWindow();
5055  flags |= (parent_window->Flags & ImGuiWindowFlags_NoMove); // Inherit the NoMove flag
5056 
5057  const ImVec2 content_avail = ImGui::GetContentRegionAvail();
5058  ImVec2 size = ImFloor(size_arg);
5059  const int auto_fit_axises = ((size.x == 0.0f) ? (1 << ImGuiAxis_X) : 0x00) | ((size.y == 0.0f) ? (1 << ImGuiAxis_Y) : 0x00);
5060  if (size.x <= 0.0f)
5061  size.x = ImMax(content_avail.x + size.x, 4.0f); // Arbitrary minimum child size (0.0f causing too much issues)
5062  if (size.y <= 0.0f)
5063  size.y = ImMax(content_avail.y + size.y, 4.0f);
5064 
5065  const float backup_border_size = g.Style.ChildBorderSize;
5066  if (!border)
5067  g.Style.ChildBorderSize = 0.0f;
5068  flags |= extra_flags;
5069 
5070  char title[256];
5071  if (name)
5072  ImFormatString(title, IM_ARRAYSIZE(title), "%s/%s_%08X", parent_window->Name, name, id);
5073  else
5074  ImFormatString(title, IM_ARRAYSIZE(title), "%s/%08X", parent_window->Name, id);
5075 
5077  bool ret = ImGui::Begin(title, NULL, flags);
5078  ImGuiWindow* child_window = ImGui::GetCurrentWindow();
5079  child_window->ChildId = id;
5080  child_window->AutoFitChildAxises = auto_fit_axises;
5081  g.Style.ChildBorderSize = backup_border_size;
5082 
5083  // Process navigation-in immediately so NavInit can run on first frame
5084  if (!(flags & ImGuiWindowFlags_NavFlattened) && (child_window->DC.NavLayerActiveMask != 0 || child_window->DC.NavHasScroll) && g.NavActivateId == id)
5085  {
5086  ImGui::FocusWindow(child_window);
5087  ImGui::NavInitWindow(child_window, false);
5088  ImGui::SetActiveID(id+1, child_window); // Steal ActiveId with a dummy id so that key-press won't activate child item
5089  g.ActiveIdSource = ImGuiInputSource_Nav;
5090  }
5091 
5092  return ret;
5093 }
5094 
5095 bool ImGui::BeginChild(const char* str_id, const ImVec2& size_arg, bool border, ImGuiWindowFlags extra_flags)
5096 {
5097  ImGuiWindow* window = GetCurrentWindow();
5098  return BeginChildEx(str_id, window->GetID(str_id), size_arg, border, extra_flags);
5099 }
5100 
5101 bool ImGui::BeginChild(ImGuiID id, const ImVec2& size_arg, bool border, ImGuiWindowFlags extra_flags)
5102 {
5103  IM_ASSERT(id != 0);
5104  return BeginChildEx(NULL, id, size_arg, border, extra_flags);
5105 }
5106 
5108 {
5109  ImGuiContext& g = *GImGui;
5110  ImGuiWindow* window = g.CurrentWindow;
5111 
5112  IM_ASSERT(window->Flags & ImGuiWindowFlags_ChildWindow); // Mismatched BeginChild()/EndChild() callss
5113  if (window->BeginCount > 1)
5114  {
5115  End();
5116  }
5117  else
5118  {
5119  // When using auto-filling child window, we don't provide full width/height to ItemSize so that it doesn't feed back into automatic size-fitting.
5120  ImVec2 sz = GetWindowSize();
5121  if (window->AutoFitChildAxises & (1 << ImGuiAxis_X)) // Arbitrary minimum zero-ish child size of 4.0f causes less trouble than a 0.0f
5122  sz.x = ImMax(4.0f, sz.x);
5123  if (window->AutoFitChildAxises & (1 << ImGuiAxis_Y))
5124  sz.y = ImMax(4.0f, sz.y);
5125  End();
5126 
5127  ImGuiWindow* parent_window = g.CurrentWindow;
5128  ImRect bb(parent_window->DC.CursorPos, parent_window->DC.CursorPos + sz);
5129  ItemSize(sz);
5130  if ((window->DC.NavLayerActiveMask != 0 || window->DC.NavHasScroll) && !(window->Flags & ImGuiWindowFlags_NavFlattened))
5131  {
5132  ItemAdd(bb, window->ChildId);
5133  RenderNavHighlight(bb, window->ChildId);
5134 
5135  // When browsing a window that has no activable items (scroll only) we keep a highlight on the child
5136  if (window->DC.NavLayerActiveMask == 0 && window == g.NavWindow)
5138  }
5139  else
5140  {
5141  // Not navigable into
5142  ItemAdd(bb, 0);
5143  }
5144  }
5145 }
5146 
5147 // Helper to create a child window / scrolling region that looks like a normal widget frame.
5149 {
5150  ImGuiContext& g = *GImGui;
5151  const ImGuiStyle& style = g.Style;
5157 }
5158 
5160 {
5161  EndChild();
5162  PopStyleVar(3);
5163  PopStyleColor();
5164 }
5165 
5166 // Save and compare stack sizes on Begin()/End() to detect usage errors
5167 static void CheckStacksSize(ImGuiWindow* window, bool write)
5168 {
5169  // NOT checking: DC.ItemWidth, DC.AllowKeyboardFocus, DC.ButtonRepeat, DC.TextWrapPos (per window) to allow user to conveniently push once and not pop (they are cleared on Begin)
5170  ImGuiContext& g = *GImGui;
5171  int* p_backup = &window->DC.StackSizesBackup[0];
5172  { int current = window->IDStack.Size; if (write) *p_backup = current; else IM_ASSERT(*p_backup == current && "PushID/PopID or TreeNode/TreePop Mismatch!"); p_backup++; } // Too few or too many PopID()/TreePop()
5173  { int current = window->DC.GroupStack.Size; if (write) *p_backup = current; else IM_ASSERT(*p_backup == current && "BeginGroup/EndGroup Mismatch!"); p_backup++; } // Too few or too many EndGroup()
5174  { int current = g.CurrentPopupStack.Size; if (write) *p_backup = current; else IM_ASSERT(*p_backup == current && "BeginMenu/EndMenu or BeginPopup/EndPopup Mismatch"); p_backup++;}// Too few or too many EndMenu()/EndPopup()
5175  { int current = g.ColorModifiers.Size; if (write) *p_backup = current; else IM_ASSERT(*p_backup == current && "PushStyleColor/PopStyleColor Mismatch!"); p_backup++; } // Too few or too many PopStyleColor()
5176  { int current = g.StyleModifiers.Size; if (write) *p_backup = current; else IM_ASSERT(*p_backup == current && "PushStyleVar/PopStyleVar Mismatch!"); p_backup++; } // Too few or too many PopStyleVar()
5177  { int current = g.FontStack.Size; if (write) *p_backup = current; else IM_ASSERT(*p_backup == current && "PushFont/PopFont Mismatch!"); p_backup++; } // Too few or too many PopFont()
5178  IM_ASSERT(p_backup == window->DC.StackSizesBackup + IM_ARRAYSIZE(window->DC.StackSizesBackup));
5179 }
5180 
5182 {
5185 };
5186 
5188 {
5189  const ImGuiStyle& style = GImGui->Style;
5190 
5191  // r_avoid = the rectangle to avoid (e.g. for tooltip it is a rectangle around the mouse cursor which we want to avoid. for popups it's a small point around the cursor.)
5192  // r_outer = the visible area rectangle, minus safe area padding. If our popup size won't fit because of safe area padding we ignore it.
5193  ImVec2 safe_padding = style.DisplaySafeAreaPadding;
5194  ImRect r_outer(GetViewportRect());
5195  r_outer.Expand(ImVec2((size.x - r_outer.GetWidth() > safe_padding.x*2) ? -safe_padding.x : 0.0f, (size.y - r_outer.GetHeight() > safe_padding.y*2) ? -safe_padding.y : 0.0f));
5196  ImVec2 base_pos_clamped = ImClamp(ref_pos, r_outer.Min, r_outer.Max - size);
5197  //GImGui->OverlayDrawList.AddRect(r_avoid.Min, r_avoid.Max, IM_COL32(255,0,0,255));
5198  //GImGui->OverlayDrawList.AddRect(r_outer.Min, r_outer.Max, IM_COL32(0,255,0,255));
5199 
5200  // Combo Box policy (we want a connecting edge)
5201  if (policy == ImGuiPopupPositionPolicy_ComboBox)
5202  {
5204  for (int n = (*last_dir != ImGuiDir_None) ? -1 : 0; n < ImGuiDir_Count_; n++)
5205  {
5206  const ImGuiDir dir = (n == -1) ? *last_dir : dir_prefered_order[n];
5207  if (n != -1 && dir == *last_dir) // Already tried this direction?
5208  continue;
5209  ImVec2 pos;
5210  if (dir == ImGuiDir_Down) pos = ImVec2(r_avoid.Min.x, r_avoid.Max.y); // Below, Toward Right (default)
5211  if (dir == ImGuiDir_Right) pos = ImVec2(r_avoid.Min.x, r_avoid.Min.y - size.y); // Above, Toward Right
5212  if (dir == ImGuiDir_Left) pos = ImVec2(r_avoid.Max.x - size.x, r_avoid.Max.y); // Below, Toward Left
5213  if (dir == ImGuiDir_Up) pos = ImVec2(r_avoid.Max.x - size.x, r_avoid.Min.y - size.y); // Above, Toward Left
5214  if (!r_outer.Contains(ImRect(pos, pos + size)))
5215  continue;
5216  *last_dir = dir;
5217  return pos;
5218  }
5219  }
5220 
5221  // Default popup policy
5223  for (int n = (*last_dir != ImGuiDir_None) ? -1 : 0; n < ImGuiDir_Count_; n++)
5224  {
5225  const ImGuiDir dir = (n == -1) ? *last_dir : dir_prefered_order[n];
5226  if (n != -1 && dir == *last_dir) // Already tried this direction?
5227  continue;
5228  float avail_w = (dir == ImGuiDir_Left ? r_avoid.Min.x : r_outer.Max.x) - (dir == ImGuiDir_Right ? r_avoid.Max.x : r_outer.Min.x);
5229  float avail_h = (dir == ImGuiDir_Up ? r_avoid.Min.y : r_outer.Max.y) - (dir == ImGuiDir_Down ? r_avoid.Max.y : r_outer.Min.y);
5230  if (avail_w < size.x || avail_h < size.y)
5231  continue;
5232  ImVec2 pos;
5233  pos.x = (dir == ImGuiDir_Left) ? r_avoid.Min.x - size.x : (dir == ImGuiDir_Right) ? r_avoid.Max.x : base_pos_clamped.x;
5234  pos.y = (dir == ImGuiDir_Up) ? r_avoid.Min.y - size.y : (dir == ImGuiDir_Down) ? r_avoid.Max.y : base_pos_clamped.y;
5235  *last_dir = dir;
5236  return pos;
5237  }
5238 
5239  // Fallback, try to keep within display
5240  *last_dir = ImGuiDir_None;
5241  ImVec2 pos = ref_pos;
5242  pos.x = ImMax(ImMin(pos.x + size.x, r_outer.Max.x) - size.x, r_outer.Min.x);
5243  pos.y = ImMax(ImMin(pos.y + size.y, r_outer.Max.y) - size.y, r_outer.Min.y);
5244  return pos;
5245 }
5246 
5248 {
5252 }
5253 
5255 {
5256  ImGuiContext& g = *GImGui;
5257  ImGuiID id = ImHash(name, 0);
5258  return (ImGuiWindow*)g.WindowsById.GetVoidPtr(id);
5259 }
5260 
5262 {
5263  ImGuiContext& g = *GImGui;
5264 
5265  // Create window the first time
5266  ImGuiWindow* window = IM_NEW(ImGuiWindow)(&g, name);
5267  window->Flags = flags;
5268  g.WindowsById.SetVoidPtr(window->ID, window);
5269 
5270  // User can disable loading and saving of settings. Tooltip and child windows also don't store settings.
5272  {
5273  // Retrieve settings from .ini file
5274  // Use SetWindowPos() or SetNextWindowPos() with the appropriate condition flag to change the initial position of a window.
5275  window->Pos = window->PosFloat = ImVec2(60, 60);
5276 
5277  if (ImGuiWindowSettings* settings = ImGui::FindWindowSettings(window->ID))
5278  {
5280  window->PosFloat = settings->Pos;
5281  window->Pos = ImFloor(window->PosFloat);
5282  window->Collapsed = settings->Collapsed;
5283  if (ImLengthSqr(settings->Size) > 0.00001f)
5284  size = settings->Size;
5285  }
5286  }
5287  window->Size = window->SizeFull = window->SizeFullAtLastBegin = size;
5288 
5290  {
5291  window->AutoFitFramesX = window->AutoFitFramesY = 2;
5292  window->AutoFitOnlyGrows = false;
5293  }
5294  else
5295  {
5296  if (window->Size.x <= 0.0f)
5297  window->AutoFitFramesX = 2;
5298  if (window->Size.y <= 0.0f)
5299  window->AutoFitFramesY = 2;
5300  window->AutoFitOnlyGrows = (window->AutoFitFramesX > 0) || (window->AutoFitFramesY > 0);
5301  }
5302 
5304  g.Windows.insert(g.Windows.begin(), window); // Quite slow but rare and only once
5305  else
5306  g.Windows.push_back(window);
5307  return window;
5308 }
5309 
5311 {
5312  ImGuiContext& g = *GImGui;
5313  if (g.NextWindowData.SizeConstraintCond != 0)
5314  {
5315  // Using -1,-1 on either X/Y axis to preserve the current size.
5316  ImRect cr = g.NextWindowData.SizeConstraintRect;
5317  new_size.x = (cr.Min.x >= 0 && cr.Max.x >= 0) ? ImClamp(new_size.x, cr.Min.x, cr.Max.x) : window->SizeFull.x;
5318  new_size.y = (cr.Min.y >= 0 && cr.Max.y >= 0) ? ImClamp(new_size.y, cr.Min.y, cr.Max.y) : window->SizeFull.y;
5319  if (g.NextWindowData.SizeCallback)
5320  {
5322  data.UserData = g.NextWindowData.SizeCallbackUserData;
5323  data.Pos = window->Pos;
5324  data.CurrentSize = window->SizeFull;
5325  data.DesiredSize = new_size;
5326  g.NextWindowData.SizeCallback(&data);
5327  new_size = data.DesiredSize;
5328  }
5329  }
5330 
5331  // Minimum size
5333  {
5334  new_size = ImMax(new_size, g.Style.WindowMinSize);
5335  new_size.y = ImMax(new_size.y, window->TitleBarHeight() + window->MenuBarHeight() + ImMax(0.0f, g.Style.WindowRounding - 1.0f)); // Reduce artifacts with very small windows
5336  }
5337  return new_size;
5338 }
5339 
5341 {
5342  ImVec2 sz;
5343  sz.x = (float)(int)((window->SizeContentsExplicit.x != 0.0f) ? window->SizeContentsExplicit.x : (window->DC.CursorMaxPos.x - window->Pos.x + window->Scroll.x));
5344  sz.y = (float)(int)((window->SizeContentsExplicit.y != 0.0f) ? window->SizeContentsExplicit.y : (window->DC.CursorMaxPos.y - window->Pos.y + window->Scroll.y));
5345  return sz + window->WindowPadding;
5346 }
5347 
5348 static ImVec2 CalcSizeAutoFit(ImGuiWindow* window, const ImVec2& size_contents)
5349 {
5350  ImGuiContext& g = *GImGui;
5351  ImGuiStyle& style = g.Style;
5352  ImGuiWindowFlags flags = window->Flags;
5353  ImVec2 size_auto_fit;
5354  if ((flags & ImGuiWindowFlags_Tooltip) != 0)
5355  {
5356  // Tooltip always resize. We keep the spacing symmetric on both axises for aesthetic purpose.
5357  size_auto_fit = size_contents;
5358  }
5359  else
5360  {
5361  // When the window cannot fit all contents (either because of constraints, either because screen is too small): we are growing the size on the other axis to compensate for expected scrollbar. FIXME: Might turn bigger than DisplaySize-WindowPadding.
5362  size_auto_fit = ImClamp(size_contents, style.WindowMinSize, ImMax(style.WindowMinSize, g.IO.DisplaySize - g.Style.DisplaySafeAreaPadding));
5363  ImVec2 size_auto_fit_after_constraint = CalcSizeAfterConstraint(window, size_auto_fit);
5364  if (size_auto_fit_after_constraint.x < size_contents.x && !(flags & ImGuiWindowFlags_NoScrollbar) && (flags & ImGuiWindowFlags_HorizontalScrollbar))
5365  size_auto_fit.y += style.ScrollbarSize;
5366  if (size_auto_fit_after_constraint.y < size_contents.y && !(flags & ImGuiWindowFlags_NoScrollbar))
5367  size_auto_fit.x += style.ScrollbarSize;
5368  }
5369  return size_auto_fit;
5370 }
5371 
5372 static float GetScrollMaxX(ImGuiWindow* window)
5373 {
5374  return ImMax(0.0f, window->SizeContents.x - (window->SizeFull.x - window->ScrollbarSizes.x));
5375 }
5376 
5377 static float GetScrollMaxY(ImGuiWindow* window)
5378 {
5379  return ImMax(0.0f, window->SizeContents.y - (window->SizeFull.y - window->ScrollbarSizes.y));
5380 }
5381 
5383 {
5384  ImVec2 scroll = window->Scroll;
5385  float cr_x = window->ScrollTargetCenterRatio.x;
5386  float cr_y = window->ScrollTargetCenterRatio.y;
5387  if (window->ScrollTarget.x < FLT_MAX)
5388  scroll.x = window->ScrollTarget.x - cr_x * (window->SizeFull.x - window->ScrollbarSizes.x);
5389  if (window->ScrollTarget.y < FLT_MAX)
5390  scroll.y = window->ScrollTarget.y - (1.0f - cr_y) * (window->TitleBarHeight() + window->MenuBarHeight()) - cr_y * (window->SizeFull.y - window->ScrollbarSizes.y);
5391  scroll = ImMax(scroll, ImVec2(0.0f, 0.0f));
5392  if (!window->Collapsed && !window->SkipItems)
5393  {
5394  scroll.x = ImMin(scroll.x, GetScrollMaxX(window));
5395  scroll.y = ImMin(scroll.y, GetScrollMaxY(window));
5396  }
5397  return scroll;
5398 }
5399 
5401 {
5403  return ImGuiCol_PopupBg;
5405  return ImGuiCol_ChildBg;
5406  return ImGuiCol_WindowBg;
5407 }
5408 
5409 static void CalcResizePosSizeFromAnyCorner(ImGuiWindow* window, const ImVec2& corner_target, const ImVec2& corner_norm, ImVec2* out_pos, ImVec2* out_size)
5410 {
5411  ImVec2 pos_min = ImLerp(corner_target, window->Pos, corner_norm); // Expected window upper-left
5412  ImVec2 pos_max = ImLerp(window->Pos + window->Size, corner_target, corner_norm); // Expected window lower-right
5413  ImVec2 size_expected = pos_max - pos_min;
5414  ImVec2 size_constrained = CalcSizeAfterConstraint(window, size_expected);
5415  *out_pos = pos_min;
5416  if (corner_norm.x == 0.0f)
5417  out_pos->x -= (size_constrained.x - size_expected.x);
5418  if (corner_norm.y == 0.0f)
5419  out_pos->y -= (size_constrained.y - size_expected.y);
5420  *out_size = size_constrained;
5421 }
5422 
5424 {
5427  int AngleMin12, AngleMax12;
5428 };
5429 
5431 {
5432  { ImVec2(1,1), ImVec2(-1,-1), 0, 3 }, // Lower right
5433  { ImVec2(0,1), ImVec2(+1,-1), 3, 6 }, // Lower left
5434  { ImVec2(0,0), ImVec2(+1,+1), 6, 9 }, // Upper left
5435  { ImVec2(1,0), ImVec2(-1,+1), 9,12 }, // Upper right
5436 };
5437 
5438 static ImRect GetBorderRect(ImGuiWindow* window, int border_n, float perp_padding, float thickness)
5439 {
5440  ImRect rect = window->Rect();
5441  if (thickness == 0.0f) rect.Max -= ImVec2(1,1);
5442  if (border_n == 0) return ImRect(rect.Min.x + perp_padding, rect.Min.y, rect.Max.x - perp_padding, rect.Min.y + thickness);
5443  if (border_n == 1) return ImRect(rect.Max.x - thickness, rect.Min.y + perp_padding, rect.Max.x, rect.Max.y - perp_padding);
5444  if (border_n == 2) return ImRect(rect.Min.x + perp_padding, rect.Max.y - thickness, rect.Max.x - perp_padding, rect.Max.y);
5445  if (border_n == 3) return ImRect(rect.Min.x, rect.Min.y + perp_padding, rect.Min.x + thickness, rect.Max.y - perp_padding);
5446  IM_ASSERT(0);
5447  return ImRect();
5448 }
5449 
5450 // Handle resize for: Resize Grips, Borders, Gamepad
5451 static void ImGui::UpdateManualResize(ImGuiWindow* window, const ImVec2& size_auto_fit, int* border_held, int resize_grip_count, ImU32 resize_grip_col[4])
5452 {
5453  ImGuiContext& g = *GImGui;
5454  ImGuiWindowFlags flags = window->Flags;
5456  return;
5457 
5458  const int resize_border_count = (flags & ImGuiWindowFlags_ResizeFromAnySide) ? 4 : 0;
5459  const float grip_draw_size = (float)(int)ImMax(g.FontSize * 1.35f, window->WindowRounding + 1.0f + g.FontSize * 0.2f);
5460  const float grip_hover_size = (float)(int)(grip_draw_size * 0.75f);
5461 
5462  ImVec2 pos_target(FLT_MAX, FLT_MAX);
5463  ImVec2 size_target(FLT_MAX, FLT_MAX);
5464 
5465  // Manual resize grips
5466  PushID("#RESIZE");
5467  for (int resize_grip_n = 0; resize_grip_n < resize_grip_count; resize_grip_n++)
5468  {
5469  const ImGuiResizeGripDef& grip = resize_grip_def[resize_grip_n];
5470  const ImVec2 corner = ImLerp(window->Pos, window->Pos + window->Size, grip.CornerPos);
5471 
5472  // Using the FlattenChilds button flag we make the resize button accessible even if we are hovering over a child window
5473  ImRect resize_rect(corner, corner + grip.InnerDir * grip_hover_size);
5474  resize_rect.FixInverted();
5475  bool hovered, held;
5476  ButtonBehavior(resize_rect, window->GetID((void*)(intptr_t)resize_grip_n), &hovered, &held, ImGuiButtonFlags_FlattenChildren | ImGuiButtonFlags_NoNavFocus);
5477  if (hovered || held)
5478  g.MouseCursor = (resize_grip_n & 1) ? ImGuiMouseCursor_ResizeNESW : ImGuiMouseCursor_ResizeNWSE;
5479 
5480  if (g.HoveredWindow == window && held && g.IO.MouseDoubleClicked[0] && resize_grip_n == 0)
5481  {
5482  // Manual auto-fit when double-clicking
5483  size_target = CalcSizeAfterConstraint(window, size_auto_fit);
5484  ClearActiveID();
5485  }
5486  else if (held)
5487  {
5488  // Resize from any of the four corners
5489  // We don't use an incremental MouseDelta but rather compute an absolute target size based on mouse position
5490  ImVec2 corner_target = g.IO.MousePos - g.ActiveIdClickOffset + resize_rect.GetSize() * grip.CornerPos; // Corner of the window corresponding to our corner grip
5491  CalcResizePosSizeFromAnyCorner(window, corner_target, grip.CornerPos, &pos_target, &size_target);
5492  }
5493  if (resize_grip_n == 0 || held || hovered)
5494  resize_grip_col[resize_grip_n] = GetColorU32(held ? ImGuiCol_ResizeGripActive : hovered ? ImGuiCol_ResizeGripHovered : ImGuiCol_ResizeGrip);
5495  }
5496  for (int border_n = 0; border_n < resize_border_count; border_n++)
5497  {
5498  const float BORDER_SIZE = 5.0f; // FIXME: Only works _inside_ window because of HoveredWindow check.
5499  const float BORDER_APPEAR_TIMER = 0.05f; // Reduce visual noise
5500  bool hovered, held;
5501  ImRect border_rect = GetBorderRect(window, border_n, grip_hover_size, BORDER_SIZE);
5502  ButtonBehavior(border_rect, window->GetID((void*)(intptr_t)(border_n + 4)), &hovered, &held, ImGuiButtonFlags_FlattenChildren);
5503  if ((hovered && g.HoveredIdTimer > BORDER_APPEAR_TIMER) || held)
5504  {
5505  g.MouseCursor = (border_n & 1) ? ImGuiMouseCursor_ResizeEW : ImGuiMouseCursor_ResizeNS;
5506  if (held) *border_held = border_n;
5507  }
5508  if (held)
5509  {
5510  ImVec2 border_target = window->Pos;
5511  ImVec2 border_posn;
5512  if (border_n == 0) { border_posn = ImVec2(0, 0); border_target.y = (g.IO.MousePos.y - g.ActiveIdClickOffset.y); }
5513  if (border_n == 1) { border_posn = ImVec2(1, 0); border_target.x = (g.IO.MousePos.x - g.ActiveIdClickOffset.x + BORDER_SIZE); }
5514  if (border_n == 2) { border_posn = ImVec2(0, 1); border_target.y = (g.IO.MousePos.y - g.ActiveIdClickOffset.y + BORDER_SIZE); }
5515  if (border_n == 3) { border_posn = ImVec2(0, 0); border_target.x = (g.IO.MousePos.x - g.ActiveIdClickOffset.x); }
5516  CalcResizePosSizeFromAnyCorner(window, border_target, border_posn, &pos_target, &size_target);
5517  }
5518  }
5519  PopID();
5520 
5521  // Navigation/gamepad resize
5522  if (g.NavWindowingTarget == window)
5523  {
5524  ImVec2 nav_resize_delta;
5525  if (g.NavWindowingInputSource == ImGuiInputSource_NavKeyboard && g.IO.KeyShift)
5527  if (g.NavWindowingInputSource == ImGuiInputSource_NavGamepad)
5529  if (nav_resize_delta.x != 0.0f || nav_resize_delta.y != 0.0f)
5530  {
5531  const float NAV_RESIZE_SPEED = 600.0f;
5532  nav_resize_delta *= ImFloor(NAV_RESIZE_SPEED * g.IO.DeltaTime * ImMin(g.IO.DisplayFramebufferScale.x, g.IO.DisplayFramebufferScale.y));
5533  g.NavWindowingToggleLayer = false;
5534  g.NavDisableMouseHover = true;
5535  resize_grip_col[0] = GetColorU32(ImGuiCol_ResizeGripActive);
5536  // FIXME-NAV: Should store and accumulate into a separate size buffer to handle sizing constraints properly, right now a constraint will make us stuck.
5537  size_target = CalcSizeAfterConstraint(window, window->SizeFull + nav_resize_delta);
5538  }
5539  }
5540 
5541  // Apply back modified position/size to window
5542  if (size_target.x != FLT_MAX)
5543  {
5544  window->SizeFull = size_target;
5545  MarkIniSettingsDirty(window);
5546  }
5547  if (pos_target.x != FLT_MAX)
5548  {
5549  window->Pos = window->PosFloat = ImFloor(pos_target);
5550  MarkIniSettingsDirty(window);
5551  }
5552 
5553  window->Size = window->SizeFull;
5554 }
5555 
5556 // Push a new ImGui window to add widgets to.
5557 // - A default window called "Debug" is automatically stacked at the beginning of every frame so you can use widgets without explicitly calling a Begin/End pair.
5558 // - Begin/End can be called multiple times during the frame with the same window name to append content.
5559 // - The window name is used as a unique identifier to preserve window information across frames (and save rudimentary information to the .ini file).
5560 // You can use the "##" or "###" markers to use the same label with different id, or same id with different label. See documentation at the top of this file.
5561 // - Return false when window is collapsed, so you can early out in your code. You always need to call ImGui::End() even if false is returned.
5562 // - Passing 'bool* p_open' displays a Close button on the upper-right corner of the window, the pointed value will be set to false when the button is pressed.
5563 bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
5564 {
5565  ImGuiContext& g = *GImGui;
5566  const ImGuiStyle& style = g.Style;
5567  IM_ASSERT(name != NULL); // Window name required
5568  IM_ASSERT(g.Initialized); // Forgot to call ImGui::NewFrame()
5569  IM_ASSERT(g.FrameCountEnded != g.FrameCount); // Called ImGui::Render() or ImGui::EndFrame() and haven't called ImGui::NewFrame() again yet
5570 
5571  // Find or create
5572  ImGuiWindow* window = FindWindowByName(name);
5573  if (!window)
5574  {
5575  ImVec2 size_on_first_use = (g.NextWindowData.SizeCond != 0) ? g.NextWindowData.SizeVal : ImVec2(0.0f, 0.0f); // Any condition flag will do since we are creating a new window here.
5576  window = CreateNewWindow(name, size_on_first_use, flags);
5577  }
5578 
5579  // Automatically disable manual moving/resizing when NoInputs is set
5582 
5585 
5586  const int current_frame = g.FrameCount;
5587  const bool first_begin_of_the_frame = (window->LastFrameActive != current_frame);
5588  if (first_begin_of_the_frame)
5589  window->Flags = (ImGuiWindowFlags)flags;
5590  else
5591  flags = window->Flags;
5592 
5593  // Update the Appearing flag
5594  bool window_just_activated_by_user = (window->LastFrameActive < current_frame - 1); // Not using !WasActive because the implicit "Debug" window would always toggle off->on
5595  const bool window_just_appearing_after_hidden_for_resize = (window->HiddenFrames == 1);
5597  {
5598  ImGuiPopupRef& popup_ref = g.OpenPopupStack[g.CurrentPopupStack.Size];
5599  window_just_activated_by_user |= (window->PopupId != popup_ref.PopupId); // We recycle popups so treat window as activated if popup id changed
5600  window_just_activated_by_user |= (window != popup_ref.Window);
5601  }
5602  window->Appearing = (window_just_activated_by_user || window_just_appearing_after_hidden_for_resize);
5603  window->CloseButton = (p_open != NULL);
5604  if (window->Appearing)
5606 
5607  // Parent window is latched only on the first call to Begin() of the frame, so further append-calls can be done from a different window stack
5608  ImGuiWindow* parent_window_in_stack = g.CurrentWindowStack.empty() ? NULL : g.CurrentWindowStack.back();
5609  ImGuiWindow* parent_window = first_begin_of_the_frame ? ((flags & (ImGuiWindowFlags_ChildWindow | ImGuiWindowFlags_Popup)) ? parent_window_in_stack : NULL) : window->ParentWindow;
5610  IM_ASSERT(parent_window != NULL || !(flags & ImGuiWindowFlags_ChildWindow));
5611 
5612  // Add to stack
5613  g.CurrentWindowStack.push_back(window);
5614  SetCurrentWindow(window);
5615  CheckStacksSize(window, true);
5617  {
5618  ImGuiPopupRef& popup_ref = g.OpenPopupStack[g.CurrentPopupStack.Size];
5619  popup_ref.Window = window;
5620  g.CurrentPopupStack.push_back(popup_ref);
5621  window->PopupId = popup_ref.PopupId;
5622  }
5623 
5624  if (window_just_appearing_after_hidden_for_resize && !(flags & ImGuiWindowFlags_ChildWindow))
5625  window->NavLastIds[0] = 0;
5626 
5627  // Process SetNextWindow***() calls
5628  bool window_pos_set_by_api = false;
5629  bool window_size_x_set_by_api = false, window_size_y_set_by_api = false;
5630  if (g.NextWindowData.PosCond)
5631  {
5632  window_pos_set_by_api = (window->SetWindowPosAllowFlags & g.NextWindowData.PosCond) != 0;
5633  if (window_pos_set_by_api && ImLengthSqr(g.NextWindowData.PosPivotVal) > 0.00001f)
5634  {
5635  // May be processed on the next frame if this is our first frame and we are measuring size
5636  // FIXME: Look into removing the branch so everything can go through this same code path for consistency.
5637  window->SetWindowPosVal = g.NextWindowData.PosVal;
5638  window->SetWindowPosPivot = g.NextWindowData.PosPivotVal;
5640  }
5641  else
5642  {
5643  SetWindowPos(window, g.NextWindowData.PosVal, g.NextWindowData.PosCond);
5644  }
5645  g.NextWindowData.PosCond = 0;
5646  }
5647  if (g.NextWindowData.SizeCond)
5648  {
5649  window_size_x_set_by_api = (window->SetWindowSizeAllowFlags & g.NextWindowData.SizeCond) != 0 && (g.NextWindowData.SizeVal.x > 0.0f);
5650  window_size_y_set_by_api = (window->SetWindowSizeAllowFlags & g.NextWindowData.SizeCond) != 0 && (g.NextWindowData.SizeVal.y > 0.0f);
5651  SetWindowSize(window, g.NextWindowData.SizeVal, g.NextWindowData.SizeCond);
5652  g.NextWindowData.SizeCond = 0;
5653  }
5654  if (g.NextWindowData.ContentSizeCond)
5655  {
5656  // Adjust passed "client size" to become a "window size"
5657  window->SizeContentsExplicit = g.NextWindowData.ContentSizeVal;
5658  if (window->SizeContentsExplicit.y != 0.0f)
5659  window->SizeContentsExplicit.y += window->TitleBarHeight() + window->MenuBarHeight();
5660  g.NextWindowData.ContentSizeCond = 0;
5661  }
5662  else if (first_begin_of_the_frame)
5663  {
5664  window->SizeContentsExplicit = ImVec2(0.0f, 0.0f);
5665  }
5666  if (g.NextWindowData.CollapsedCond)
5667  {
5668  SetWindowCollapsed(window, g.NextWindowData.CollapsedVal, g.NextWindowData.CollapsedCond);
5669  g.NextWindowData.CollapsedCond = 0;
5670  }
5671  if (g.NextWindowData.FocusCond)
5672  {
5673  SetWindowFocus();
5674  g.NextWindowData.FocusCond = 0;
5675  }
5676  if (window->Appearing)
5678 
5679  // When reusing window again multiple times a frame, just append content (don't need to setup again)
5680  if (first_begin_of_the_frame)
5681  {
5682  const bool window_is_child_tooltip = (flags & ImGuiWindowFlags_ChildWindow) && (flags & ImGuiWindowFlags_Tooltip); // FIXME-WIP: Undocumented behavior of Child+Tooltip for pinned tooltip (#1345)
5683 
5684  // Initialize
5685  window->ParentWindow = parent_window;
5686  window->RootWindow = window->RootWindowForTitleBarHighlight = window->RootWindowForTabbing = window->RootWindowForNav = window;
5687  if (parent_window && (flags & ImGuiWindowFlags_ChildWindow) && !window_is_child_tooltip)
5688  window->RootWindow = parent_window->RootWindow;
5690  window->RootWindowForTitleBarHighlight = window->RootWindowForTabbing = parent_window->RootWindowForTitleBarHighlight; // Same value in master branch, will differ for docking
5692  window->RootWindowForNav = window->RootWindowForNav->ParentWindow;
5693 
5694  window->Active = true;
5695  window->BeginOrderWithinParent = 0;
5696  window->BeginOrderWithinContext = g.WindowsActiveCount++;
5697  window->BeginCount = 0;
5698  window->ClipRect = ImVec4(-FLT_MAX,-FLT_MAX,+FLT_MAX,+FLT_MAX);
5699  window->LastFrameActive = current_frame;
5700  window->IDStack.resize(1);
5701 
5702  // Lock window rounding, border size and rounding so that altering the border sizes for children doesn't have side-effects.
5705  window->WindowPadding = style.WindowPadding;
5707  window->WindowPadding = ImVec2(0.0f, (flags & ImGuiWindowFlags_MenuBar) ? style.WindowPadding.y : 0.0f);
5708 
5709  // Collapse window by double-clicking on title bar
5710  // At this point we don't have a clipping rectangle setup yet, so we can use the title bar area for hit detection and drawing
5712  {
5713  ImRect title_bar_rect = window->TitleBarRect();
5714  if (window->CollapseToggleWanted || (g.HoveredWindow == window && IsMouseHoveringRect(title_bar_rect.Min, title_bar_rect.Max) && g.IO.MouseDoubleClicked[0]))
5715  {
5716  window->Collapsed = !window->Collapsed;
5717  MarkIniSettingsDirty(window);
5718  FocusWindow(window);
5719  }
5720  }
5721  else
5722  {
5723  window->Collapsed = false;
5724  }
5725  window->CollapseToggleWanted = false;
5726 
5727  // SIZE
5728 
5729  // Update contents size from last frame for auto-fitting (unless explicitly specified)
5730  window->SizeContents = CalcSizeContents(window);
5731 
5732  // Hide popup/tooltip window when re-opening while we measure size (because we recycle the windows)
5733  if (window->HiddenFrames > 0)
5734  window->HiddenFrames--;
5735  if ((flags & (ImGuiWindowFlags_Popup | ImGuiWindowFlags_Tooltip)) != 0 && window_just_activated_by_user)
5736  {
5737  window->HiddenFrames = 1;
5739  {
5740  if (!window_size_x_set_by_api)
5741  window->Size.x = window->SizeFull.x = 0.f;
5742  if (!window_size_y_set_by_api)
5743  window->Size.y = window->SizeFull.y = 0.f;
5744  window->SizeContents = ImVec2(0.f, 0.f);
5745  }
5746  }
5747 
5748  // Calculate auto-fit size, handle automatic resize
5749  const ImVec2 size_auto_fit = CalcSizeAutoFit(window, window->SizeContents);
5750  ImVec2 size_full_modified(FLT_MAX, FLT_MAX);
5752  {
5753  // Using SetNextWindowSize() overrides ImGuiWindowFlags_AlwaysAutoResize, so it can be used on tooltips/popups, etc.
5754  if (!window_size_x_set_by_api)
5755  window->SizeFull.x = size_full_modified.x = size_auto_fit.x;
5756  if (!window_size_y_set_by_api)
5757  window->SizeFull.y = size_full_modified.y = size_auto_fit.y;
5758  }
5759  else if (window->AutoFitFramesX > 0 || window->AutoFitFramesY > 0)
5760  {
5761  // Auto-fit only grows during the first few frames
5762  // We still process initial auto-fit on collapsed windows to get a window width, but otherwise don't honor ImGuiWindowFlags_AlwaysAutoResize when collapsed.
5763  if (!window_size_x_set_by_api && window->AutoFitFramesX > 0)
5764  window->SizeFull.x = size_full_modified.x = window->AutoFitOnlyGrows ? ImMax(window->SizeFull.x, size_auto_fit.x) : size_auto_fit.x;
5765  if (!window_size_y_set_by_api && window->AutoFitFramesY > 0)
5766  window->SizeFull.y = size_full_modified.y = window->AutoFitOnlyGrows ? ImMax(window->SizeFull.y, size_auto_fit.y) : size_auto_fit.y;
5767  if (!window->Collapsed)
5768  MarkIniSettingsDirty(window);
5769  }
5770 
5771  // Apply minimum/maximum window size constraints and final size
5772  window->SizeFull = CalcSizeAfterConstraint(window, window->SizeFull);
5773  window->Size = window->Collapsed && !(flags & ImGuiWindowFlags_ChildWindow) ? window->TitleBarRect().GetSize() : window->SizeFull;
5774 
5775  // SCROLLBAR STATUS
5776 
5777  // Update scrollbar status (based on the Size that was effective during last frame or the auto-resized Size).
5778  if (!window->Collapsed)
5779  {
5780  // When reading the current size we need to read it after size constraints have been applied
5781  float size_x_for_scrollbars = size_full_modified.x != FLT_MAX ? window->SizeFull.x : window->SizeFullAtLastBegin.x;
5782  float size_y_for_scrollbars = size_full_modified.y != FLT_MAX ? window->SizeFull.y : window->SizeFullAtLastBegin.y;
5783  window->ScrollbarY = (flags & ImGuiWindowFlags_AlwaysVerticalScrollbar) || ((window->SizeContents.y > size_y_for_scrollbars) && !(flags & ImGuiWindowFlags_NoScrollbar));
5784  window->ScrollbarX = (flags & ImGuiWindowFlags_AlwaysHorizontalScrollbar) || ((window->SizeContents.x > size_x_for_scrollbars - (window->ScrollbarY ? style.ScrollbarSize : 0.0f)) && !(flags & ImGuiWindowFlags_NoScrollbar) && (flags & ImGuiWindowFlags_HorizontalScrollbar));
5785  if (window->ScrollbarX && !window->ScrollbarY)
5786  window->ScrollbarY = (window->SizeContents.y > size_y_for_scrollbars - style.ScrollbarSize) && !(flags & ImGuiWindowFlags_NoScrollbar);
5787  window->ScrollbarSizes = ImVec2(window->ScrollbarY ? style.ScrollbarSize : 0.0f, window->ScrollbarX ? style.ScrollbarSize : 0.0f);
5788  }
5789 
5790  // POSITION
5791 
5792  // Popup latch its initial position, will position itself when it appears next frame
5793  if (window_just_activated_by_user)
5794  {
5796  if ((flags & ImGuiWindowFlags_Popup) != 0 && !window_pos_set_by_api)
5797  window->Pos = window->PosFloat = g.CurrentPopupStack.back().OpenPopupPos;
5798  }
5799 
5800  // Position child window
5802  {
5803  window->BeginOrderWithinParent = parent_window->DC.ChildWindows.Size;
5804  parent_window->DC.ChildWindows.push_back(window);
5805  if (!(flags & ImGuiWindowFlags_Popup) && !window_pos_set_by_api && !window_is_child_tooltip)
5806  window->Pos = window->PosFloat = parent_window->DC.CursorPos;
5807  }
5808 
5809  const bool window_pos_with_pivot = (window->SetWindowPosVal.x != FLT_MAX && window->HiddenFrames == 0);
5810  if (window_pos_with_pivot)
5811  {
5812  // Position given a pivot (e.g. for centering)
5813  SetWindowPos(window, ImMax(style.DisplaySafeAreaPadding, window->SetWindowPosVal - window->SizeFull * window->SetWindowPosPivot), 0);
5814  }
5815  else if (flags & ImGuiWindowFlags_ChildMenu)
5816  {
5817  // Child menus typically request _any_ position within the parent menu item, and then our FindBestPopupWindowPos() function will move the new menu outside the parent bounds.
5818  // This is how we end up with child menus appearing (most-commonly) on the right of the parent menu.
5819  IM_ASSERT(window_pos_set_by_api);
5820  float horizontal_overlap = style.ItemSpacing.x; // We want some overlap to convey the relative depth of each popup (currently the amount of overlap it is hard-coded to style.ItemSpacing.x, may need to introduce another style value).
5821  ImGuiWindow* parent_menu = parent_window_in_stack;
5822  ImRect rect_to_avoid;
5823  if (parent_menu->DC.MenuBarAppending)
5824  rect_to_avoid = ImRect(-FLT_MAX, parent_menu->Pos.y + parent_menu->TitleBarHeight(), FLT_MAX, parent_menu->Pos.y + parent_menu->TitleBarHeight() + parent_menu->MenuBarHeight());
5825  else
5826  rect_to_avoid = ImRect(parent_menu->Pos.x + horizontal_overlap, -FLT_MAX, parent_menu->Pos.x + parent_menu->Size.x - horizontal_overlap - parent_menu->ScrollbarSizes.x, FLT_MAX);
5827  window->PosFloat = FindBestWindowPosForPopup(window->PosFloat, window->Size, &window->AutoPosLastDirection, rect_to_avoid);
5828  }
5829  else if ((flags & ImGuiWindowFlags_Popup) != 0 && !window_pos_set_by_api && window_just_appearing_after_hidden_for_resize)
5830  {
5831  ImRect rect_to_avoid(window->PosFloat.x - 1, window->PosFloat.y - 1, window->PosFloat.x + 1, window->PosFloat.y + 1);
5832  window->PosFloat = FindBestWindowPosForPopup(window->PosFloat, window->Size, &window->AutoPosLastDirection, rect_to_avoid);
5833  }
5834 
5835  // Position tooltip (always follows mouse)
5836  if ((flags & ImGuiWindowFlags_Tooltip) != 0 && !window_pos_set_by_api && !window_is_child_tooltip)
5837  {
5838  float sc = g.Style.MouseCursorScale;
5839  ImVec2 ref_pos = (!g.NavDisableHighlight && g.NavDisableMouseHover) ? NavCalcPreferredMousePos() : g.IO.MousePos;
5840  ImRect rect_to_avoid;
5841  if (!g.NavDisableHighlight && g.NavDisableMouseHover && !(g.IO.ConfigFlags & ImGuiConfigFlags_NavMoveMouse))
5842  rect_to_avoid = ImRect(ref_pos.x - 16, ref_pos.y - 8, ref_pos.x + 16, ref_pos.y + 8);
5843  else
5844  rect_to_avoid = ImRect(ref_pos.x - 16, ref_pos.y - 8, ref_pos.x + 24 * sc, ref_pos.y + 24 * sc); // FIXME: Hard-coded based on mouse cursor shape expectation. Exact dimension not very important.
5845  window->PosFloat = FindBestWindowPosForPopup(ref_pos, window->Size, &window->AutoPosLastDirection, rect_to_avoid);
5846  if (window->AutoPosLastDirection == ImGuiDir_None)
5847  window->PosFloat = ref_pos + ImVec2(2,2); // If there's not enough room, for tooltip we prefer avoiding the cursor at all cost even if it means that part of the tooltip won't be visible.
5848  }
5849 
5850  // Clamp position so it stays visible
5852  {
5853  if (!window_pos_set_by_api && window->AutoFitFramesX <= 0 && window->AutoFitFramesY <= 0 && g.IO.DisplaySize.x > 0.0f && g.IO.DisplaySize.y > 0.0f) // Ignore zero-sized display explicitly to avoid losing positions if a window manager reports zero-sized window when initializing or minimizing.
5854  {
5855  ImVec2 padding = ImMax(style.DisplayWindowPadding, style.DisplaySafeAreaPadding);
5856  window->PosFloat = ImMax(window->PosFloat + window->Size, padding) - window->Size;
5857  window->PosFloat = ImMin(window->PosFloat, g.IO.DisplaySize - padding);
5858  }
5859  }
5860  window->Pos = ImFloor(window->PosFloat);
5861 
5862  // Default item width. Make it proportional to window size if window manually resizes
5863  if (window->Size.x > 0.0f && !(flags & ImGuiWindowFlags_Tooltip) && !(flags & ImGuiWindowFlags_AlwaysAutoResize))
5864  window->ItemWidthDefault = (float)(int)(window->Size.x * 0.65f);
5865  else
5866  window->ItemWidthDefault = (float)(int)(g.FontSize * 16.0f);
5867 
5868  // Prepare for focus requests
5869  window->FocusIdxAllRequestCurrent = (window->FocusIdxAllRequestNext == INT_MAX || window->FocusIdxAllCounter == -1) ? INT_MAX : (window->FocusIdxAllRequestNext + (window->FocusIdxAllCounter+1)) % (window->FocusIdxAllCounter+1);
5870  window->FocusIdxTabRequestCurrent = (window->FocusIdxTabRequestNext == INT_MAX || window->FocusIdxTabCounter == -1) ? INT_MAX : (window->FocusIdxTabRequestNext + (window->FocusIdxTabCounter+1)) % (window->FocusIdxTabCounter+1);
5871  window->FocusIdxAllCounter = window->FocusIdxTabCounter = -1;
5872  window->FocusIdxAllRequestNext = window->FocusIdxTabRequestNext = INT_MAX;
5873 
5874  // Apply scrolling
5876  window->ScrollTarget = ImVec2(FLT_MAX, FLT_MAX);
5877 
5878  // Apply focus, new windows appears in front
5879  bool want_focus = false;
5880  if (window_just_activated_by_user && !(flags & ImGuiWindowFlags_NoFocusOnAppearing))
5882  want_focus = true;
5883 
5884  // Handle manual resize: Resize Grips, Borders, Gamepad
5885  int border_held = -1;
5886  ImU32 resize_grip_col[4] = { 0 };
5887  const int resize_grip_count = (flags & ImGuiWindowFlags_ResizeFromAnySide) ? 2 : 1; // 4
5888  const float grip_draw_size = (float)(int)ImMax(g.FontSize * 1.35f, window->WindowRounding + 1.0f + g.FontSize * 0.2f);
5889  if (!window->Collapsed)
5890  UpdateManualResize(window, size_auto_fit, &border_held, resize_grip_count, &resize_grip_col[0]);
5891 
5892  // DRAWING
5893 
5894  // Setup draw list and outer clipping rectangle
5895  window->DrawList->Clear();
5896  window->DrawList->Flags = (g.Style.AntiAliasedLines ? ImDrawListFlags_AntiAliasedLines : 0) | (g.Style.AntiAliasedFill ? ImDrawListFlags_AntiAliasedFill : 0);
5897  window->DrawList->PushTextureID(g.Font->ContainerAtlas->TexID);
5898  ImRect viewport_rect(GetViewportRect());
5899  if ((flags & ImGuiWindowFlags_ChildWindow) && !(flags & ImGuiWindowFlags_Popup) && !window_is_child_tooltip)
5900  PushClipRect(parent_window->ClipRect.Min, parent_window->ClipRect.Max, true);
5901  else
5902  PushClipRect(viewport_rect.Min, viewport_rect.Max, true);
5903 
5904  // Draw modal window background (darkens what is behind them)
5905  if ((flags & ImGuiWindowFlags_Modal) != 0 && window == GetFrontMostModalRootWindow())
5906  window->DrawList->AddRectFilled(viewport_rect.Min, viewport_rect.Max, GetColorU32(ImGuiCol_ModalWindowDarkening, g.ModalWindowDarkeningRatio));
5907 
5908  // Draw navigation selection/windowing rectangle background
5909  if (g.NavWindowingTarget == window)
5910  {
5911  ImRect bb = window->Rect();
5912  bb.Expand(g.FontSize);
5913  if (!bb.Contains(viewport_rect)) // Avoid drawing if the window covers all the viewport anyway
5914  window->DrawList->AddRectFilled(bb.Min, bb.Max, GetColorU32(ImGuiCol_NavWindowingHighlight, g.NavWindowingHighlightAlpha * 0.25f), g.Style.WindowRounding);
5915  }
5916 
5917  // Draw window + handle manual resize
5918  const float window_rounding = window->WindowRounding;
5919  const float window_border_size = window->WindowBorderSize;
5920  const bool title_bar_is_highlight = want_focus || (g.NavWindow && window->RootWindowForTitleBarHighlight == g.NavWindow->RootWindowForTitleBarHighlight);
5921  const ImRect title_bar_rect = window->TitleBarRect();
5922  if (window->Collapsed)
5923  {
5924  // Title bar only
5925  float backup_border_size = style.FrameBorderSize;
5926  g.Style.FrameBorderSize = window->WindowBorderSize;
5927  ImU32 title_bar_col = GetColorU32((title_bar_is_highlight && !g.NavDisableHighlight) ? ImGuiCol_TitleBgActive : ImGuiCol_TitleBgCollapsed);
5928  RenderFrame(title_bar_rect.Min, title_bar_rect.Max, title_bar_col, true, window_rounding);
5929  g.Style.FrameBorderSize = backup_border_size;
5930  }
5931  else
5932  {
5933  // Window background
5935  if (g.NextWindowData.BgAlphaCond != 0)
5936  {
5937  bg_col = (bg_col & ~IM_COL32_A_MASK) | (IM_F32_TO_INT8_SAT(g.NextWindowData.BgAlphaVal) << IM_COL32_A_SHIFT);
5938  g.NextWindowData.BgAlphaCond = 0;
5939  }
5940  window->DrawList->AddRectFilled(window->Pos+ImVec2(0,window->TitleBarHeight()), window->Pos+window->Size, bg_col, window_rounding, (flags & ImGuiWindowFlags_NoTitleBar) ? ImDrawCornerFlags_All : ImDrawCornerFlags_Bot);
5941 
5942  // Title bar
5943  ImU32 title_bar_col = GetColorU32(window->Collapsed ? ImGuiCol_TitleBgCollapsed : title_bar_is_highlight ? ImGuiCol_TitleBgActive : ImGuiCol_TitleBg);
5945  window->DrawList->AddRectFilled(title_bar_rect.Min, title_bar_rect.Max, title_bar_col, window_rounding, ImDrawCornerFlags_Top);
5946 
5947  // Menu bar
5949  {
5950  ImRect menu_bar_rect = window->MenuBarRect();
5951  menu_bar_rect.ClipWith(window->Rect()); // Soft clipping, in particular child window don't have minimum size covering the menu bar so this is useful for them.
5952  window->DrawList->AddRectFilled(menu_bar_rect.Min, menu_bar_rect.Max, GetColorU32(ImGuiCol_MenuBarBg), (flags & ImGuiWindowFlags_NoTitleBar) ? window_rounding : 0.0f, ImDrawCornerFlags_Top);
5953  if (style.FrameBorderSize > 0.0f && menu_bar_rect.Max.y < window->Pos.y + window->Size.y)
5954  window->DrawList->AddLine(menu_bar_rect.GetBL(), menu_bar_rect.GetBR(), GetColorU32(ImGuiCol_Border), style.FrameBorderSize);
5955  }
5956 
5957  // Scrollbars
5958  if (window->ScrollbarX)
5960  if (window->ScrollbarY)
5962 
5963  // Render resize grips (after their input handling so we don't have a frame of latency)
5965  {
5966  for (int resize_grip_n = 0; resize_grip_n < resize_grip_count; resize_grip_n++)
5967  {
5968  const ImGuiResizeGripDef& grip = resize_grip_def[resize_grip_n];
5969  const ImVec2 corner = ImLerp(window->Pos, window->Pos + window->Size, grip.CornerPos);
5970  window->DrawList->PathLineTo(corner + grip.InnerDir * ((resize_grip_n & 1) ? ImVec2(window_border_size, grip_draw_size) : ImVec2(grip_draw_size, window_border_size)));
5971  window->DrawList->PathLineTo(corner + grip.InnerDir * ((resize_grip_n & 1) ? ImVec2(grip_draw_size, window_border_size) : ImVec2(window_border_size, grip_draw_size)));
5972  window->DrawList->PathArcToFast(ImVec2(corner.x + grip.InnerDir.x * (window_rounding + window_border_size), corner.y + grip.InnerDir.y * (window_rounding + window_border_size)), window_rounding, grip.AngleMin12, grip.AngleMax12);
5973  window->DrawList->PathFillConvex(resize_grip_col[resize_grip_n]);
5974  }
5975  }
5976 
5977  // Borders
5978  if (window_border_size > 0.0f)
5979  window->DrawList->AddRect(window->Pos, window->Pos+window->Size, GetColorU32(ImGuiCol_Border), window_rounding, ImDrawCornerFlags_All, window_border_size);
5980  if (border_held != -1)
5981  {
5982  ImRect border = GetBorderRect(window, border_held, grip_draw_size, 0.0f);
5983  window->DrawList->AddLine(border.Min, border.Max, GetColorU32(ImGuiCol_SeparatorActive), ImMax(1.0f, window_border_size));
5984  }
5985  if (style.FrameBorderSize > 0 && !(flags & ImGuiWindowFlags_NoTitleBar))
5986  window->DrawList->AddLine(title_bar_rect.GetBL() + ImVec2(style.WindowBorderSize, -1), title_bar_rect.GetBR() + ImVec2(-style.WindowBorderSize,-1), GetColorU32(ImGuiCol_Border), style.FrameBorderSize);
5987  }
5988 
5989  // Draw navigation selection/windowing rectangle border
5990  if (g.NavWindowingTarget == window)
5991  {
5992  float rounding = ImMax(window->WindowRounding, g.Style.WindowRounding);
5993  ImRect bb = window->Rect();
5994  bb.Expand(g.FontSize);
5995  if (bb.Contains(viewport_rect)) // If a window fits the entire viewport, adjust its highlight inward
5996  {
5997  bb.Expand(-g.FontSize - 1.0f);
5998  rounding = window->WindowRounding;
5999  }
6000  window->DrawList->AddRect(bb.Min, bb.Max, GetColorU32(ImGuiCol_NavWindowingHighlight, g.NavWindowingHighlightAlpha), rounding, ~0, 3.0f);
6001  }
6002 
6003  // Store a backup of SizeFull which we will use next frame to decide if we need scrollbars.
6004  window->SizeFullAtLastBegin = window->SizeFull;
6005 
6006  // Update ContentsRegionMax. All the variable it depends on are set above in this function.
6007  window->ContentsRegionRect.Min.x = -window->Scroll.x + window->WindowPadding.x;
6008  window->ContentsRegionRect.Min.y = -window->Scroll.y + window->WindowPadding.y + window->TitleBarHeight() + window->MenuBarHeight();
6009  window->ContentsRegionRect.Max.x = -window->Scroll.x - window->WindowPadding.x + (window->SizeContentsExplicit.x != 0.0f ? window->SizeContentsExplicit.x : (window->Size.x - window->ScrollbarSizes.x));
6010  window->ContentsRegionRect.Max.y = -window->Scroll.y - window->WindowPadding.y + (window->SizeContentsExplicit.y != 0.0f ? window->SizeContentsExplicit.y : (window->Size.y - window->ScrollbarSizes.y));
6011 
6012  // Setup drawing context
6013  // (NB: That term "drawing context / DC" lost its meaning a long time ago. Initially was meant to hold transient data only. Nowadays difference between window-> and window->DC-> is dubious.)
6014  window->DC.IndentX = 0.0f + window->WindowPadding.x - window->Scroll.x;
6015  window->DC.GroupOffsetX = 0.0f;
6016  window->DC.ColumnsOffsetX = 0.0f;
6017  window->DC.CursorStartPos = window->Pos + ImVec2(window->DC.IndentX + window->DC.ColumnsOffsetX, window->TitleBarHeight() + window->MenuBarHeight() + window->WindowPadding.y - window->Scroll.y);
6018  window->DC.CursorPos = window->DC.CursorStartPos;
6019  window->DC.CursorPosPrevLine = window->DC.CursorPos;
6020  window->DC.CursorMaxPos = window->DC.CursorStartPos;
6021  window->DC.CurrentLineHeight = window->DC.PrevLineHeight = 0.0f;
6022  window->DC.CurrentLineTextBaseOffset = window->DC.PrevLineTextBaseOffset = 0.0f;
6023  window->DC.NavHideHighlightOneFrame = false;
6024  window->DC.NavHasScroll = (GetScrollMaxY() > 0.0f);
6025  window->DC.NavLayerActiveMask = window->DC.NavLayerActiveMaskNext;
6026  window->DC.NavLayerActiveMaskNext = 0x00;
6027  window->DC.MenuBarAppending = false;
6028  window->DC.MenuBarOffsetX = ImMax(window->WindowPadding.x, style.ItemSpacing.x);
6029  window->DC.LogLinePosY = window->DC.CursorPos.y - 9999.0f;
6030  window->DC.ChildWindows.resize(0);
6032  window->DC.ParentLayoutType = parent_window ? parent_window->DC.LayoutType : ImGuiLayoutType_Vertical;
6034  window->DC.ItemWidth = window->ItemWidthDefault;
6035  window->DC.TextWrapPos = -1.0f; // disabled
6036  window->DC.ItemFlagsStack.resize(0);
6037  window->DC.ItemWidthStack.resize(0);
6038  window->DC.TextWrapPosStack.resize(0);
6039  window->DC.ColumnsSet = NULL;
6040  window->DC.TreeDepth = 0;
6041  window->DC.TreeDepthMayJumpToParentOnPop = 0x00;
6042  window->DC.StateStorage = &window->StateStorage;
6043  window->DC.GroupStack.resize(0);
6044  window->MenuColumns.Update(3, style.ItemSpacing.x, window_just_activated_by_user);
6045 
6046  if ((flags & ImGuiWindowFlags_ChildWindow) && (window->DC.ItemFlags != parent_window->DC.ItemFlags))
6047  {
6048  window->DC.ItemFlags = parent_window->DC.ItemFlags;
6049  window->DC.ItemFlagsStack.push_back(window->DC.ItemFlags);
6050  }
6051 
6052  if (window->AutoFitFramesX > 0)
6053  window->AutoFitFramesX--;
6054  if (window->AutoFitFramesY > 0)
6055  window->AutoFitFramesY--;
6056 
6057  // Apply focus (we need to call FocusWindow() AFTER setting DC.CursorStartPos so our initial navigation reference rectangle can start around there)
6058  if (want_focus)
6059  {
6060  FocusWindow(window);
6061  NavInitWindow(window, false);
6062  }
6063 
6064  // Title bar
6066  {
6067  // Close & collapse button are on layer 1 (same as menus) and don't default focus
6068  const ImGuiItemFlags item_flags_backup = window->DC.ItemFlags;
6070  window->DC.NavLayerCurrent++;
6071  window->DC.NavLayerCurrentMask <<= 1;
6072 
6073  // Collapse button
6075  {
6076  ImGuiID id = window->GetID("#COLLAPSE");
6077  ImRect bb(window->Pos + style.FramePadding + ImVec2(1,1), window->Pos + style.FramePadding + ImVec2(g.FontSize,g.FontSize) - ImVec2(1,1));
6078  ItemAdd(bb, id); // To allow navigation
6079  if (ButtonBehavior(bb, id, NULL, NULL))
6080  window->CollapseToggleWanted = true; // Defer collapsing to next frame as we are too far in the Begin() function
6081  RenderNavHighlight(bb, id);
6082  RenderTriangle(window->Pos + style.FramePadding, window->Collapsed ? ImGuiDir_Right : ImGuiDir_Down, 1.0f);
6083  }
6084 
6085  // Close button
6086  if (p_open != NULL)
6087  {
6088  const float PAD = 2.0f;
6089  const float rad = (window->TitleBarHeight() - PAD*2.0f) * 0.5f;
6090  if (CloseButton(window->GetID("#CLOSE"), window->Rect().GetTR() + ImVec2(-PAD - rad, PAD + rad), rad))
6091  *p_open = false;
6092  }
6093 
6094  window->DC.NavLayerCurrent--;
6095  window->DC.NavLayerCurrentMask >>= 1;
6096  window->DC.ItemFlags = item_flags_backup;
6097 
6098  // Title text (FIXME: refactor text alignment facilities along with RenderText helpers)
6099  ImVec2 text_size = CalcTextSize(name, NULL, true);
6100  ImRect text_r = title_bar_rect;
6101  float pad_left = (flags & ImGuiWindowFlags_NoCollapse) == 0 ? (style.FramePadding.x + g.FontSize + style.ItemInnerSpacing.x) : style.FramePadding.x;
6102  float pad_right = (p_open != NULL) ? (style.FramePadding.x + g.FontSize + style.ItemInnerSpacing.x) : style.FramePadding.x;
6103  if (style.WindowTitleAlign.x > 0.0f) pad_right = ImLerp(pad_right, pad_left, style.WindowTitleAlign.x);
6104  text_r.Min.x += pad_left;
6105  text_r.Max.x -= pad_right;
6106  ImRect clip_rect = text_r;
6107  clip_rect.Max.x = window->Pos.x + window->Size.x - (p_open ? title_bar_rect.GetHeight() - 3 : style.FramePadding.x); // Match the size of CloseButton()
6108  RenderTextClipped(text_r.Min, text_r.Max, name, NULL, &text_size, style.WindowTitleAlign, &clip_rect);
6109  }
6110 
6111  // Save clipped aabb so we can access it in constant-time in FindHoveredWindow()
6112  window->WindowRectClipped = window->Rect();
6113  window->WindowRectClipped.ClipWith(window->ClipRect);
6114 
6115  // Pressing CTRL+C while holding on a window copy its content to the clipboard
6116  // This works but 1. doesn't handle multiple Begin/End pairs, 2. recursing into another Begin/End pair - so we need to work that out and add better logging scope.
6117  // Maybe we can support CTRL+C on every element?
6118  /*
6119  if (g.ActiveId == move_id)
6120  if (g.IO.KeyCtrl && IsKeyPressedMap(ImGuiKey_C))
6121  ImGui::LogToClipboard();
6122  */
6123 
6124  // Inner rectangle
6125  // We set this up after processing the resize grip so that our clip rectangle doesn't lag by a frame
6126  // Note that if our window is collapsed we will end up with a null clipping rectangle which is the correct behavior.
6127  window->InnerRect.Min.x = title_bar_rect.Min.x + window->WindowBorderSize;
6128  window->InnerRect.Min.y = title_bar_rect.Max.y + window->MenuBarHeight() + (((flags & ImGuiWindowFlags_MenuBar) || !(flags & ImGuiWindowFlags_NoTitleBar)) ? style.FrameBorderSize : window->WindowBorderSize);
6129  window->InnerRect.Max.x = window->Pos.x + window->Size.x - window->ScrollbarSizes.x - window->WindowBorderSize;
6130  window->InnerRect.Max.y = window->Pos.y + window->Size.y - window->ScrollbarSizes.y - window->WindowBorderSize;
6131  //window->DrawList->AddRect(window->InnerRect.Min, window->InnerRect.Max, IM_COL32_WHITE);
6132 
6133  // After Begin() we fill the last item / hovered data using the title bar data. Make that a standard behavior (to allow usage of context menus on title bar only, etc.).
6134  window->DC.LastItemId = window->MoveId;
6135  window->DC.LastItemStatusFlags = IsMouseHoveringRect(title_bar_rect.Min, title_bar_rect.Max, false) ? ImGuiItemStatusFlags_HoveredRect : 0;
6136  window->DC.LastItemRect = title_bar_rect;
6137  }
6138 
6139  // Inner clipping rectangle
6140  // Force round operator last to ensure that e.g. (int)(max.x-min.x) in user's render code produce correct result.
6141  const float border_size = window->WindowBorderSize;
6142  ImRect clip_rect;
6143  clip_rect.Min.x = ImFloor(0.5f + window->InnerRect.Min.x + ImMax(0.0f, ImFloor(window->WindowPadding.x*0.5f - border_size)));
6144  clip_rect.Min.y = ImFloor(0.5f + window->InnerRect.Min.y);
6145  clip_rect.Max.x = ImFloor(0.5f + window->InnerRect.Max.x - ImMax(0.0f, ImFloor(window->WindowPadding.x*0.5f - border_size)));
6146  clip_rect.Max.y = ImFloor(0.5f + window->InnerRect.Max.y);
6147  PushClipRect(clip_rect.Min, clip_rect.Max, true);
6148 
6149  // Clear 'accessed' flag last thing (After PushClipRect which will set the flag. We want the flag to stay false when the default "Debug" window is unused)
6150  if (first_begin_of_the_frame)
6151  window->WriteAccessed = false;
6152 
6153  window->BeginCount++;
6154  g.NextWindowData.SizeConstraintCond = 0;
6155 
6156  // Child window can be out of sight and have "negative" clip windows.
6157  // Mark them as collapsed so commands are skipped earlier (we can't manually collapse because they have no title bar).
6159  {
6161  window->Collapsed = parent_window && parent_window->Collapsed;
6162 
6163  if (!(flags & ImGuiWindowFlags_AlwaysAutoResize) && window->AutoFitFramesX <= 0 && window->AutoFitFramesY <= 0)
6164  window->Collapsed |= (window->WindowRectClipped.Min.x >= window->WindowRectClipped.Max.x || window->WindowRectClipped.Min.y >= window->WindowRectClipped.Max.y);
6165 
6166  // We also hide the window from rendering because we've already added its border to the command list.
6167  // (we could perform the check earlier in the function but it is simpler at this point)
6168  if (window->Collapsed)
6169  window->Active = false;
6170  }
6171  if (style.Alpha <= 0.0f)
6172  window->Active = false;
6173 
6174  // Return false if we don't intend to display anything to allow user to perform an early out optimization
6175  window->SkipItems = (window->Collapsed || !window->Active) && window->AutoFitFramesX <= 0 && window->AutoFitFramesY <= 0;
6176  return !window->SkipItems;
6177 }
6178 
6179 // Old Begin() API with 5 parameters, avoid calling this version directly! Use SetNextWindowSize()/SetNextWindowBgAlpha() + Begin() instead.
6180 #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
6181 bool ImGui::Begin(const char* name, bool* p_open, const ImVec2& size_first_use, float bg_alpha_override, ImGuiWindowFlags flags)
6182 {
6183  // Old API feature: we could pass the initial window size as a parameter. This was misleading because it only had an effect if the window didn't have data in the .ini file.
6184  if (size_first_use.x != 0.0f || size_first_use.y != 0.0f)
6186 
6187  // Old API feature: override the window background alpha with a parameter.
6188  if (bg_alpha_override >= 0.0f)
6189  ImGui::SetNextWindowBgAlpha(bg_alpha_override);
6190 
6191  return ImGui::Begin(name, p_open, flags);
6192 }
6193 #endif // IMGUI_DISABLE_OBSOLETE_FUNCTIONS
6194 
6196 {
6197  ImGuiContext& g = *GImGui;
6198  ImGuiWindow* window = g.CurrentWindow;
6199 
6200  if (window->DC.ColumnsSet != NULL)
6201  EndColumns();
6202  PopClipRect(); // Inner window clip rectangle
6203 
6204  // Stop logging
6205  if (!(window->Flags & ImGuiWindowFlags_ChildWindow)) // FIXME: add more options for scope of logging
6206  LogFinish();
6207 
6208  // Pop from window stack
6209  g.CurrentWindowStack.pop_back();
6210  if (window->Flags & ImGuiWindowFlags_Popup)
6211  g.CurrentPopupStack.pop_back();
6212  CheckStacksSize(window, false);
6213  SetCurrentWindow(g.CurrentWindowStack.empty() ? NULL : g.CurrentWindowStack.back());
6214 }
6215 
6216 // Vertical scrollbar
6217 // The entire piece of code below is rather confusing because:
6218 // - We handle absolute seeking (when first clicking outside the grab) and relative manipulation (afterward or when clicking inside the grab)
6219 // - We store values as normalized ratio and in a form that allows the window content to change while we are holding on a scrollbar
6220 // - We handle both horizontal and vertical scrollbars, which makes the terminology not ideal.
6222 {
6223  ImGuiContext& g = *GImGui;
6224  ImGuiWindow* window = g.CurrentWindow;
6225 
6226  const bool horizontal = (direction == ImGuiLayoutType_Horizontal);
6227  const ImGuiStyle& style = g.Style;
6228  const ImGuiID id = window->GetID(horizontal ? "#SCROLLX" : "#SCROLLY");
6229 
6230  // Render background
6231  bool other_scrollbar = (horizontal ? window->ScrollbarY : window->ScrollbarX);
6232  float other_scrollbar_size_w = other_scrollbar ? style.ScrollbarSize : 0.0f;
6233  const ImRect window_rect = window->Rect();
6234  const float border_size = window->WindowBorderSize;
6235  ImRect bb = horizontal
6236  ? ImRect(window->Pos.x + border_size, window_rect.Max.y - style.ScrollbarSize, window_rect.Max.x - other_scrollbar_size_w - border_size, window_rect.Max.y - border_size)
6237  : ImRect(window_rect.Max.x - style.ScrollbarSize, window->Pos.y + border_size, window_rect.Max.x - border_size, window_rect.Max.y - other_scrollbar_size_w - border_size);
6238  if (!horizontal)
6239  bb.Min.y += window->TitleBarHeight() + ((window->Flags & ImGuiWindowFlags_MenuBar) ? window->MenuBarHeight() : 0.0f);
6240  if (bb.GetWidth() <= 0.0f || bb.GetHeight() <= 0.0f)
6241  return;
6242 
6243  int window_rounding_corners;
6244  if (horizontal)
6245  window_rounding_corners = ImDrawCornerFlags_BotLeft | (other_scrollbar ? 0 : ImDrawCornerFlags_BotRight);
6246  else
6247  window_rounding_corners = (((window->Flags & ImGuiWindowFlags_NoTitleBar) && !(window->Flags & ImGuiWindowFlags_MenuBar)) ? ImDrawCornerFlags_TopRight : 0) | (other_scrollbar ? 0 : ImDrawCornerFlags_BotRight);
6248  window->DrawList->AddRectFilled(bb.Min, bb.Max, GetColorU32(ImGuiCol_ScrollbarBg), window->WindowRounding, window_rounding_corners);
6249  bb.Expand(ImVec2(-ImClamp((float)(int)((bb.Max.x - bb.Min.x - 2.0f) * 0.5f), 0.0f, 3.0f), -ImClamp((float)(int)((bb.Max.y - bb.Min.y - 2.0f) * 0.5f), 0.0f, 3.0f)));
6250 
6251  // V denote the main, longer axis of the scrollbar (= height for a vertical scrollbar)
6252  float scrollbar_size_v = horizontal ? bb.GetWidth() : bb.GetHeight();
6253  float scroll_v = horizontal ? window->Scroll.x : window->Scroll.y;
6254  float win_size_avail_v = (horizontal ? window->SizeFull.x : window->SizeFull.y) - other_scrollbar_size_w;
6255  float win_size_contents_v = horizontal ? window->SizeContents.x : window->SizeContents.y;
6256 
6257  // Calculate the height of our grabbable box. It generally represent the amount visible (vs the total scrollable amount)
6258  // But we maintain a minimum size in pixel to allow for the user to still aim inside.
6259  IM_ASSERT(ImMax(win_size_contents_v, win_size_avail_v) > 0.0f); // Adding this assert to check if the ImMax(XXX,1.0f) is still needed. PLEASE CONTACT ME if this triggers.
6260  const float win_size_v = ImMax(ImMax(win_size_contents_v, win_size_avail_v), 1.0f);
6261  const float grab_h_pixels = ImClamp(scrollbar_size_v * (win_size_avail_v / win_size_v), style.GrabMinSize, scrollbar_size_v);
6262  const float grab_h_norm = grab_h_pixels / scrollbar_size_v;
6263 
6264  // Handle input right away. None of the code of Begin() is relying on scrolling position before calling Scrollbar().
6265  bool held = false;
6266  bool hovered = false;
6267  const bool previously_held = (g.ActiveId == id);
6268  ButtonBehavior(bb, id, &hovered, &held, ImGuiButtonFlags_NoNavFocus);
6269 
6270  float scroll_max = ImMax(1.0f, win_size_contents_v - win_size_avail_v);
6271  float scroll_ratio = ImSaturate(scroll_v / scroll_max);
6272  float grab_v_norm = scroll_ratio * (scrollbar_size_v - grab_h_pixels) / scrollbar_size_v;
6273  if (held && grab_h_norm < 1.0f)
6274  {
6275  float scrollbar_pos_v = horizontal ? bb.Min.x : bb.Min.y;
6276  float mouse_pos_v = horizontal ? g.IO.MousePos.x : g.IO.MousePos.y;
6277  float* click_delta_to_grab_center_v = horizontal ? &g.ScrollbarClickDeltaToGrabCenter.x : &g.ScrollbarClickDeltaToGrabCenter.y;
6278 
6279  // Click position in scrollbar normalized space (0.0f->1.0f)
6280  const float clicked_v_norm = ImSaturate((mouse_pos_v - scrollbar_pos_v) / scrollbar_size_v);
6281  SetHoveredID(id);
6282 
6283  bool seek_absolute = false;
6284  if (!previously_held)
6285  {
6286  // On initial click calculate the distance between mouse and the center of the grab
6287  if (clicked_v_norm >= grab_v_norm && clicked_v_norm <= grab_v_norm + grab_h_norm)
6288  {
6289  *click_delta_to_grab_center_v = clicked_v_norm - grab_v_norm - grab_h_norm*0.5f;
6290  }
6291  else
6292  {
6293  seek_absolute = true;
6294  *click_delta_to_grab_center_v = 0.0f;
6295  }
6296  }
6297 
6298  // Apply scroll
6299  // It is ok to modify Scroll here because we are being called in Begin() after the calculation of SizeContents and before setting up our starting position
6300  const float scroll_v_norm = ImSaturate((clicked_v_norm - *click_delta_to_grab_center_v - grab_h_norm*0.5f) / (1.0f - grab_h_norm));
6301  scroll_v = (float)(int)(0.5f + scroll_v_norm * scroll_max);//(win_size_contents_v - win_size_v));
6302  if (horizontal)
6303  window->Scroll.x = scroll_v;
6304  else
6305  window->Scroll.y = scroll_v;
6306 
6307  // Update values for rendering
6308  scroll_ratio = ImSaturate(scroll_v / scroll_max);
6309  grab_v_norm = scroll_ratio * (scrollbar_size_v - grab_h_pixels) / scrollbar_size_v;
6310 
6311  // Update distance to grab now that we have seeked and saturated
6312  if (seek_absolute)
6313  *click_delta_to_grab_center_v = clicked_v_norm - grab_v_norm - grab_h_norm*0.5f;
6314  }
6315 
6316  // Render
6318  ImRect grab_rect;
6319  if (horizontal)
6320  grab_rect = ImRect(ImLerp(bb.Min.x, bb.Max.x, grab_v_norm), bb.Min.y, ImMin(ImLerp(bb.Min.x, bb.Max.x, grab_v_norm) + grab_h_pixels, window_rect.Max.x), bb.Max.y);
6321  else
6322  grab_rect = ImRect(bb.Min.x, ImLerp(bb.Min.y, bb.Max.y, grab_v_norm), bb.Max.x, ImMin(ImLerp(bb.Min.y, bb.Max.y, grab_v_norm) + grab_h_pixels, window_rect.Max.y));
6323  window->DrawList->AddRectFilled(grab_rect.Min, grab_rect.Max, grab_col, style.ScrollbarRounding);
6324 }
6325 
6327 {
6328  ImGuiContext& g = *GImGui;
6329  ImGuiWindow* current_front_window = g.Windows.back();
6330  if (current_front_window == window || current_front_window->RootWindow == window)
6331  return;
6332  for (int i = g.Windows.Size - 2; i >= 0; i--) // We can ignore the front most window
6333  if (g.Windows[i] == window)
6334  {
6335  g.Windows.erase(g.Windows.Data + i);
6336  g.Windows.push_back(window);
6337  break;
6338  }
6339 }
6340 
6342 {
6343  ImGuiContext& g = *GImGui;
6344  if (g.Windows[0] == window)
6345  return;
6346  for (int i = 0; i < g.Windows.Size; i++)
6347  if (g.Windows[i] == window)
6348  {
6349  memmove(&g.Windows[1], &g.Windows[0], (size_t)i * sizeof(ImGuiWindow*));
6350  g.Windows[0] = window;
6351  break;
6352  }
6353 }
6354 
6355 // Moving window to front of display and set focus (which happens to be back of our sorted list)
6357 {
6358  ImGuiContext& g = *GImGui;
6359 
6360  if (g.NavWindow != window)
6361  {
6362  g.NavWindow = window;
6363  if (window && g.NavDisableMouseHover)
6364  g.NavMousePosDirty = true;
6365  g.NavInitRequest = false;
6366  g.NavId = window ? window->NavLastIds[0] : 0; // Restore NavId
6367  g.NavIdIsAlive = false;
6368  g.NavLayer = 0;
6369  }
6370 
6371  // Passing NULL allow to disable keyboard focus
6372  if (!window)
6373  return;
6374 
6375  // Move the root window to the top of the pile
6376  if (window->RootWindow)
6377  window = window->RootWindow;
6378 
6379  // Steal focus on active widgets
6380  if (window->Flags & ImGuiWindowFlags_Popup) // FIXME: This statement should be unnecessary. Need further testing before removing it..
6381  if (g.ActiveId != 0 && g.ActiveIdWindow && g.ActiveIdWindow->RootWindow != window)
6382  ClearActiveID();
6383 
6384  // Bring to front
6386  BringWindowToFront(window);
6387 }
6388 
6390 {
6391  ImGuiContext& g = *GImGui;
6392  for (int i = g.Windows.Size - 1; i >= 0; i--)
6393  if (g.Windows[i] != ignore_window && g.Windows[i]->WasActive && !(g.Windows[i]->Flags & ImGuiWindowFlags_ChildWindow))
6394  {
6395  ImGuiWindow* focus_window = NavRestoreLastChildNavWindow(g.Windows[i]);
6396  FocusWindow(focus_window);
6397  return;
6398  }
6399 }
6400 
6401 void ImGui::PushItemWidth(float item_width)
6402 {
6403  ImGuiWindow* window = GetCurrentWindow();
6404  window->DC.ItemWidth = (item_width == 0.0f ? window->ItemWidthDefault : item_width);
6405  window->DC.ItemWidthStack.push_back(window->DC.ItemWidth);
6406 }
6407 
6409 {
6410  ImGuiWindow* window = GetCurrentWindow();
6411  const ImGuiStyle& style = GImGui->Style;
6412  if (w_full <= 0.0f)
6413  w_full = CalcItemWidth();
6414  const float w_item_one = ImMax(1.0f, (float)(int)((w_full - (style.ItemInnerSpacing.x) * (components-1)) / (float)components));
6415  const float w_item_last = ImMax(1.0f, (float)(int)(w_full - (w_item_one + style.ItemInnerSpacing.x) * (components-1)));
6416  window->DC.ItemWidthStack.push_back(w_item_last);
6417  for (int i = 0; i < components-1; i++)
6418  window->DC.ItemWidthStack.push_back(w_item_one);
6419  window->DC.ItemWidth = window->DC.ItemWidthStack.back();
6420 }
6421 
6423 {
6424  ImGuiWindow* window = GetCurrentWindow();
6425  window->DC.ItemWidthStack.pop_back();
6426  window->DC.ItemWidth = window->DC.ItemWidthStack.empty() ? window->ItemWidthDefault : window->DC.ItemWidthStack.back();
6427 }
6428 
6430 {
6431  ImGuiWindow* window = GetCurrentWindowRead();
6432  float w = window->DC.ItemWidth;
6433  if (w < 0.0f)
6434  {
6435  // Align to a right-side limit. We include 1 frame padding in the calculation because this is how the width is always used (we add 2 frame padding to it), but we could move that responsibility to the widget as well.
6436  float width_to_right_edge = GetContentRegionAvail().x;
6437  w = ImMax(1.0f, width_to_right_edge + w);
6438  }
6439  w = (float)(int)w;
6440  return w;
6441 }
6442 
6444 {
6445  ImGuiContext& g = *GImGui;
6446  return g.IO.FontDefault ? g.IO.FontDefault : g.IO.Fonts->Fonts[0];
6447 }
6448 
6450 {
6451  ImGuiContext& g = *GImGui;
6452  IM_ASSERT(font && font->IsLoaded()); // Font Atlas not created. Did you call io.Fonts->GetTexDataAsRGBA32 / GetTexDataAsAlpha8 ?
6453  IM_ASSERT(font->Scale > 0.0f);
6454  g.Font = font;
6455  g.FontBaseSize = g.IO.FontGlobalScale * g.Font->FontSize * g.Font->Scale;
6456  g.FontSize = g.CurrentWindow ? g.CurrentWindow->CalcFontSize() : 0.0f;
6457 
6458  ImFontAtlas* atlas = g.Font->ContainerAtlas;
6459  g.DrawListSharedData.TexUvWhitePixel = atlas->TexUvWhitePixel;
6460  g.DrawListSharedData.Font = g.Font;
6461  g.DrawListSharedData.FontSize = g.FontSize;
6462 }
6463 
6465 {
6466  ImGuiContext& g = *GImGui;
6467  if (!font)
6468  font = GetDefaultFont();
6469  SetCurrentFont(font);
6470  g.FontStack.push_back(font);
6471  g.CurrentWindow->DrawList->PushTextureID(font->ContainerAtlas->TexID);
6472 }
6473 
6475 {
6476  ImGuiContext& g = *GImGui;
6478  g.FontStack.pop_back();
6479  SetCurrentFont(g.FontStack.empty() ? GetDefaultFont() : g.FontStack.back());
6480 }
6481 
6483 {
6484  ImGuiWindow* window = GetCurrentWindow();
6485  if (enabled)
6486  window->DC.ItemFlags |= option;
6487  else
6488  window->DC.ItemFlags &= ~option;
6489  window->DC.ItemFlagsStack.push_back(window->DC.ItemFlags);
6490 }
6491 
6493 {
6494  ImGuiWindow* window = GetCurrentWindow();
6495  window->DC.ItemFlagsStack.pop_back();
6496  window->DC.ItemFlags = window->DC.ItemFlagsStack.empty() ? ImGuiItemFlags_Default_ : window->DC.ItemFlagsStack.back();
6497 }
6498 
6499 void ImGui::PushAllowKeyboardFocus(bool allow_keyboard_focus)
6500 {
6501  PushItemFlag(ImGuiItemFlags_AllowKeyboardFocus, allow_keyboard_focus);
6502 }
6503 
6505 {
6506  PopItemFlag();
6507 }
6508 
6509 void ImGui::PushButtonRepeat(bool repeat)
6510 {
6512 }
6513 
6515 {
6516  PopItemFlag();
6517 }
6518 
6519 void ImGui::PushTextWrapPos(float wrap_pos_x)
6520 {
6521  ImGuiWindow* window = GetCurrentWindow();
6522  window->DC.TextWrapPos = wrap_pos_x;
6523  window->DC.TextWrapPosStack.push_back(wrap_pos_x);
6524 }
6525 
6527 {
6528  ImGuiWindow* window = GetCurrentWindow();
6529  window->DC.TextWrapPosStack.pop_back();
6530  window->DC.TextWrapPos = window->DC.TextWrapPosStack.empty() ? -1.0f : window->DC.TextWrapPosStack.back();
6531 }
6532 
6533 // FIXME: This may incur a round-trip (if the end user got their data from a float4) but eventually we aim to store the in-flight colors as ImU32
6535 {
6536  ImGuiContext& g = *GImGui;
6537  ImGuiColMod backup;
6538  backup.Col = idx;
6539  backup.BackupValue = g.Style.Colors[idx];
6540  g.ColorModifiers.push_back(backup);
6541  g.Style.Colors[idx] = ColorConvertU32ToFloat4(col);
6542 }
6543 
6545 {
6546  ImGuiContext& g = *GImGui;
6547  ImGuiColMod backup;
6548  backup.Col = idx;
6549  backup.BackupValue = g.Style.Colors[idx];
6550  g.ColorModifiers.push_back(backup);
6551  g.Style.Colors[idx] = col;
6552 }
6553 
6555 {
6556  ImGuiContext& g = *GImGui;
6557  while (count > 0)
6558  {
6559  ImGuiColMod& backup = g.ColorModifiers.back();
6560  g.Style.Colors[backup.Col] = backup.BackupValue;
6561  g.ColorModifiers.pop_back();
6562  count--;
6563  }
6564 }
6565 
6567 {
6570  void* GetVarPtr(ImGuiStyle* style) const { return (void*)((unsigned char*)style + Offset); }
6571 };
6572 
6574 {
6575  { ImGuiDataType_Float, (ImU32)IM_OFFSETOF(ImGuiStyle, Alpha) }, // ImGuiStyleVar_Alpha
6576  { ImGuiDataType_Float2, (ImU32)IM_OFFSETOF(ImGuiStyle, WindowPadding) }, // ImGuiStyleVar_WindowPadding
6577  { ImGuiDataType_Float, (ImU32)IM_OFFSETOF(ImGuiStyle, WindowRounding) }, // ImGuiStyleVar_WindowRounding
6578  { ImGuiDataType_Float, (ImU32)IM_OFFSETOF(ImGuiStyle, WindowBorderSize) }, // ImGuiStyleVar_WindowBorderSize
6579  { ImGuiDataType_Float2, (ImU32)IM_OFFSETOF(ImGuiStyle, WindowMinSize) }, // ImGuiStyleVar_WindowMinSize
6580  { ImGuiDataType_Float2, (ImU32)IM_OFFSETOF(ImGuiStyle, WindowTitleAlign) }, // ImGuiStyleVar_WindowTitleAlign
6581  { ImGuiDataType_Float, (ImU32)IM_OFFSETOF(ImGuiStyle, ChildRounding) }, // ImGuiStyleVar_ChildRounding
6582  { ImGuiDataType_Float, (ImU32)IM_OFFSETOF(ImGuiStyle, ChildBorderSize) }, // ImGuiStyleVar_ChildBorderSize
6583  { ImGuiDataType_Float, (ImU32)IM_OFFSETOF(ImGuiStyle, PopupRounding) }, // ImGuiStyleVar_PopupRounding
6584  { ImGuiDataType_Float, (ImU32)IM_OFFSETOF(ImGuiStyle, PopupBorderSize) }, // ImGuiStyleVar_PopupBorderSize
6585  { ImGuiDataType_Float2, (ImU32)IM_OFFSETOF(ImGuiStyle, FramePadding) }, // ImGuiStyleVar_FramePadding
6586  { ImGuiDataType_Float, (ImU32)IM_OFFSETOF(ImGuiStyle, FrameRounding) }, // ImGuiStyleVar_FrameRounding
6587  { ImGuiDataType_Float, (ImU32)IM_OFFSETOF(ImGuiStyle, FrameBorderSize) }, // ImGuiStyleVar_FrameBorderSize
6588  { ImGuiDataType_Float2, (ImU32)IM_OFFSETOF(ImGuiStyle, ItemSpacing) }, // ImGuiStyleVar_ItemSpacing
6589  { ImGuiDataType_Float2, (ImU32)IM_OFFSETOF(ImGuiStyle, ItemInnerSpacing) }, // ImGuiStyleVar_ItemInnerSpacing
6590  { ImGuiDataType_Float, (ImU32)IM_OFFSETOF(ImGuiStyle, IndentSpacing) }, // ImGuiStyleVar_IndentSpacing
6591  { ImGuiDataType_Float, (ImU32)IM_OFFSETOF(ImGuiStyle, ScrollbarSize) }, // ImGuiStyleVar_ScrollbarSize
6592  { ImGuiDataType_Float, (ImU32)IM_OFFSETOF(ImGuiStyle, ScrollbarRounding) }, // ImGuiStyleVar_ScrollbarRounding
6593  { ImGuiDataType_Float, (ImU32)IM_OFFSETOF(ImGuiStyle, GrabMinSize) }, // ImGuiStyleVar_GrabMinSize
6594  { ImGuiDataType_Float, (ImU32)IM_OFFSETOF(ImGuiStyle, GrabRounding) }, // ImGuiStyleVar_GrabRounding
6595  { ImGuiDataType_Float2, (ImU32)IM_OFFSETOF(ImGuiStyle, ButtonTextAlign) }, // ImGuiStyleVar_ButtonTextAlign
6596 };
6597 
6599 {
6600  IM_ASSERT(idx >= 0 && idx < ImGuiStyleVar_Count_);
6602  return &GStyleVarInfo[idx];
6603 }
6604 
6606 {
6607  const ImGuiStyleVarInfo* var_info = GetStyleVarInfo(idx);
6608  if (var_info->Type == ImGuiDataType_Float)
6609  {
6610  ImGuiContext& g = *GImGui;
6611  float* pvar = (float*)var_info->GetVarPtr(&g.Style);
6612  g.StyleModifiers.push_back(ImGuiStyleMod(idx, *pvar));
6613  *pvar = val;
6614  return;
6615  }
6616  IM_ASSERT(0); // Called function with wrong-type? Variable is not a float.
6617 }
6618 
6620 {
6621  const ImGuiStyleVarInfo* var_info = GetStyleVarInfo(idx);
6622  if (var_info->Type == ImGuiDataType_Float2)
6623  {
6624  ImGuiContext& g = *GImGui;
6625  ImVec2* pvar = (ImVec2*)var_info->GetVarPtr(&g.Style);
6626  g.StyleModifiers.push_back(ImGuiStyleMod(idx, *pvar));
6627  *pvar = val;
6628  return;
6629  }
6630  IM_ASSERT(0); // Called function with wrong-type? Variable is not a ImVec2.
6631 }
6632 
6634 {
6635  ImGuiContext& g = *GImGui;
6636  while (count > 0)
6637  {
6638  ImGuiStyleMod& backup = g.StyleModifiers.back();
6639  const ImGuiStyleVarInfo* info = GetStyleVarInfo(backup.VarIdx);
6640  if (info->Type == ImGuiDataType_Float) (*(float*)info->GetVarPtr(&g.Style)) = backup.BackupFloat[0];
6641  else if (info->Type == ImGuiDataType_Float2) (*(ImVec2*)info->GetVarPtr(&g.Style)) = ImVec2(backup.BackupFloat[0], backup.BackupFloat[1]);
6642  else if (info->Type == ImGuiDataType_Int) (*(int*)info->GetVarPtr(&g.Style)) = backup.BackupInt[0];
6643  g.StyleModifiers.pop_back();
6644  count--;
6645  }
6646 }
6647 
6649 {
6650  // Create switch-case from enum with regexp: ImGuiCol_{.*}, --> case ImGuiCol_\1: return "\1";
6651  switch (idx)
6652  {
6653  case ImGuiCol_Text: return "Text";
6654  case ImGuiCol_TextDisabled: return "TextDisabled";
6655  case ImGuiCol_WindowBg: return "WindowBg";
6656  case ImGuiCol_ChildBg: return "ChildBg";
6657  case ImGuiCol_PopupBg: return "PopupBg";
6658  case ImGuiCol_Border: return "Border";
6659  case ImGuiCol_BorderShadow: return "BorderShadow";
6660  case ImGuiCol_FrameBg: return "FrameBg";
6661  case ImGuiCol_FrameBgHovered: return "FrameBgHovered";
6662  case ImGuiCol_FrameBgActive: return "FrameBgActive";
6663  case ImGuiCol_TitleBg: return "TitleBg";
6664  case ImGuiCol_TitleBgActive: return "TitleBgActive";
6665  case ImGuiCol_TitleBgCollapsed: return "TitleBgCollapsed";
6666  case ImGuiCol_MenuBarBg: return "MenuBarBg";
6667  case ImGuiCol_ScrollbarBg: return "ScrollbarBg";
6668  case ImGuiCol_ScrollbarGrab: return "ScrollbarGrab";
6669  case ImGuiCol_ScrollbarGrabHovered: return "ScrollbarGrabHovered";
6670  case ImGuiCol_ScrollbarGrabActive: return "ScrollbarGrabActive";
6671  case ImGuiCol_CheckMark: return "CheckMark";
6672  case ImGuiCol_SliderGrab: return "SliderGrab";
6673  case ImGuiCol_SliderGrabActive: return "SliderGrabActive";
6674  case ImGuiCol_Button: return "Button";
6675  case ImGuiCol_ButtonHovered: return "ButtonHovered";
6676  case ImGuiCol_ButtonActive: return "ButtonActive";
6677  case ImGuiCol_Header: return "Header";
6678  case ImGuiCol_HeaderHovered: return "HeaderHovered";
6679  case ImGuiCol_HeaderActive: return "HeaderActive";
6680  case ImGuiCol_Separator: return "Separator";
6681  case ImGuiCol_SeparatorHovered: return "SeparatorHovered";
6682  case ImGuiCol_SeparatorActive: return "SeparatorActive";
6683  case ImGuiCol_ResizeGrip: return "ResizeGrip";
6684  case ImGuiCol_ResizeGripHovered: return "ResizeGripHovered";
6685  case ImGuiCol_ResizeGripActive: return "ResizeGripActive";
6686  case ImGuiCol_CloseButton: return "CloseButton";
6687  case ImGuiCol_CloseButtonHovered: return "CloseButtonHovered";
6688  case ImGuiCol_CloseButtonActive: return "CloseButtonActive";
6689  case ImGuiCol_PlotLines: return "PlotLines";
6690  case ImGuiCol_PlotLinesHovered: return "PlotLinesHovered";
6691  case ImGuiCol_PlotHistogram: return "PlotHistogram";
6692  case ImGuiCol_PlotHistogramHovered: return "PlotHistogramHovered";
6693  case ImGuiCol_TextSelectedBg: return "TextSelectedBg";
6694  case ImGuiCol_ModalWindowDarkening: return "ModalWindowDarkening";
6695  case ImGuiCol_DragDropTarget: return "DragDropTarget";
6696  case ImGuiCol_NavHighlight: return "NavHighlight";
6697  case ImGuiCol_NavWindowingHighlight: return "NavWindowingHighlight";
6698  }
6699  IM_ASSERT(0);
6700  return "Unknown";
6701 }
6702 
6703 bool ImGui::IsWindowChildOf(ImGuiWindow* window, ImGuiWindow* potential_parent)
6704 {
6705  if (window->RootWindow == potential_parent)
6706  return true;
6707  while (window != NULL)
6708  {
6709  if (window == potential_parent)
6710  return true;
6711  window = window->ParentWindow;
6712  }
6713  return false;
6714 }
6715 
6717 {
6718  IM_ASSERT((flags & ImGuiHoveredFlags_AllowWhenOverlapped) == 0); // Flags not supported by this function
6719  ImGuiContext& g = *GImGui;
6720 
6722  {
6723  if (g.HoveredWindow == NULL)
6724  return false;
6725  }
6726  else
6727  {
6729  {
6731  if (g.HoveredRootWindow != g.CurrentWindow->RootWindow)
6732  return false;
6733  break;
6735  if (g.HoveredWindow != g.CurrentWindow->RootWindow)
6736  return false;
6737  break;
6739  if (g.HoveredWindow == NULL || !IsWindowChildOf(g.HoveredWindow, g.CurrentWindow))
6740  return false;
6741  break;
6742  default:
6743  if (g.HoveredWindow != g.CurrentWindow)
6744  return false;
6745  break;
6746  }
6747  }
6748 
6749  if (!IsWindowContentHoverable(g.HoveredRootWindow, flags))
6750  return false;
6752  if (g.ActiveId != 0 && !g.ActiveIdAllowOverlap && g.ActiveId != g.HoveredWindow->MoveId)
6753  return false;
6754  return true;
6755 }
6756 
6758 {
6759  ImGuiContext& g = *GImGui;
6760  IM_ASSERT(g.CurrentWindow); // Not inside a Begin()/End()
6761 
6763  return g.NavWindow != NULL;
6764 
6766  {
6768  return g.NavWindow && g.NavWindow->RootWindow == g.CurrentWindow->RootWindow;
6770  return g.NavWindow == g.CurrentWindow->RootWindow;
6772  return g.NavWindow && IsWindowChildOf(g.NavWindow, g.CurrentWindow);
6773  default:
6774  return g.NavWindow == g.CurrentWindow;
6775  }
6776 }
6777 
6778 // Can we focus this window with CTRL+TAB (or PadMenu + PadFocusPrev/PadFocusNext)
6780 {
6781  ImGuiContext& g = *GImGui;
6782  return window->Active && window == window->RootWindowForTabbing && (!(window->Flags & ImGuiWindowFlags_NoNavFocus) || window == g.NavWindow);
6783 }
6784 
6786 {
6787  ImGuiWindow* window = GImGui->CurrentWindow;
6788  return window->Size.x;
6789 }
6790 
6792 {
6793  ImGuiWindow* window = GImGui->CurrentWindow;
6794  return window->Size.y;
6795 }
6796 
6798 {
6799  ImGuiContext& g = *GImGui;
6800  ImGuiWindow* window = g.CurrentWindow;
6801  return window->Pos;
6802 }
6803 
6804 static void SetWindowScrollX(ImGuiWindow* window, float new_scroll_x)
6805 {
6806  window->DC.CursorMaxPos.x += window->Scroll.x; // SizeContents is generally computed based on CursorMaxPos which is affected by scroll position, so we need to apply our change to it.
6807  window->Scroll.x = new_scroll_x;
6808  window->DC.CursorMaxPos.x -= window->Scroll.x;
6809 }
6810 
6811 static void SetWindowScrollY(ImGuiWindow* window, float new_scroll_y)
6812 {
6813  window->DC.CursorMaxPos.y += window->Scroll.y; // SizeContents is generally computed based on CursorMaxPos which is affected by scroll position, so we need to apply our change to it.
6814  window->Scroll.y = new_scroll_y;
6815  window->DC.CursorMaxPos.y -= window->Scroll.y;
6816 }
6817 
6818 static void SetWindowPos(ImGuiWindow* window, const ImVec2& pos, ImGuiCond cond)
6819 {
6820  // Test condition (NB: bit 0 is always true) and clear flags for next time
6821  if (cond && (window->SetWindowPosAllowFlags & cond) == 0)
6822  return;
6824  window->SetWindowPosVal = ImVec2(FLT_MAX, FLT_MAX);
6825 
6826  // Set
6827  const ImVec2 old_pos = window->Pos;
6828  window->PosFloat = pos;
6829  window->Pos = ImFloor(pos);
6830  window->DC.CursorPos += (window->Pos - old_pos); // As we happen to move the window while it is being appended to (which is a bad idea - will smear) let's at least offset the cursor
6831  window->DC.CursorMaxPos += (window->Pos - old_pos); // And more importantly we need to adjust this so size calculation doesn't get affected.
6832 }
6833 
6834 void ImGui::SetWindowPos(const ImVec2& pos, ImGuiCond cond)
6835 {
6836  ImGuiWindow* window = GetCurrentWindowRead();
6837  SetWindowPos(window, pos, cond);
6838 }
6839 
6840 void ImGui::SetWindowPos(const char* name, const ImVec2& pos, ImGuiCond cond)
6841 {
6842  if (ImGuiWindow* window = FindWindowByName(name))
6843  SetWindowPos(window, pos, cond);
6844 }
6845 
6847 {
6848  ImGuiWindow* window = GetCurrentWindowRead();
6849  return window->Size;
6850 }
6851 
6852 static void SetWindowSize(ImGuiWindow* window, const ImVec2& size, ImGuiCond cond)
6853 {
6854  // Test condition (NB: bit 0 is always true) and clear flags for next time
6855  if (cond && (window->SetWindowSizeAllowFlags & cond) == 0)
6856  return;
6858 
6859  // Set
6860  if (size.x > 0.0f)
6861  {
6862  window->AutoFitFramesX = 0;
6863  window->SizeFull.x = size.x;
6864  }
6865  else
6866  {
6867  window->AutoFitFramesX = 2;
6868  window->AutoFitOnlyGrows = false;
6869  }
6870  if (size.y > 0.0f)
6871  {
6872  window->AutoFitFramesY = 0;
6873  window->SizeFull.y = size.y;
6874  }
6875  else
6876  {
6877  window->AutoFitFramesY = 2;
6878  window->AutoFitOnlyGrows = false;
6879  }
6880 }
6881 
6883 {
6885 }
6886 
6887 void ImGui::SetWindowSize(const char* name, const ImVec2& size, ImGuiCond cond)
6888 {
6889  if (ImGuiWindow* window = FindWindowByName(name))
6890  SetWindowSize(window, size, cond);
6891 }
6892 
6893 static void SetWindowCollapsed(ImGuiWindow* window, bool collapsed, ImGuiCond cond)
6894 {
6895  // Test condition (NB: bit 0 is always true) and clear flags for next time
6896  if (cond && (window->SetWindowCollapsedAllowFlags & cond) == 0)
6897  return;
6899 
6900  // Set
6901  window->Collapsed = collapsed;
6902 }
6903 
6904 void ImGui::SetWindowCollapsed(bool collapsed, ImGuiCond cond)
6905 {
6906  SetWindowCollapsed(GImGui->CurrentWindow, collapsed, cond);
6907 }
6908 
6910 {
6911  ImGuiWindow* window = GetCurrentWindowRead();
6912  return window->Collapsed;
6913 }
6914 
6916 {
6917  ImGuiWindow* window = GetCurrentWindowRead();
6918  return window->Appearing;
6919 }
6920 
6921 void ImGui::SetWindowCollapsed(const char* name, bool collapsed, ImGuiCond cond)
6922 {
6923  if (ImGuiWindow* window = FindWindowByName(name))
6924  SetWindowCollapsed(window, collapsed, cond);
6925 }
6926 
6928 {
6930 }
6931 
6932 void ImGui::SetWindowFocus(const char* name)
6933 {
6934  if (name)
6935  {
6936  if (ImGuiWindow* window = FindWindowByName(name))
6937  FocusWindow(window);
6938  }
6939  else
6940  {
6941  FocusWindow(NULL);
6942  }
6943 }
6944 
6945 void ImGui::SetNextWindowPos(const ImVec2& pos, ImGuiCond cond, const ImVec2& pivot)
6946 {
6947  ImGuiContext& g = *GImGui;
6948  g.NextWindowData.PosVal = pos;
6949  g.NextWindowData.PosPivotVal = pivot;
6950  g.NextWindowData.PosCond = cond ? cond : ImGuiCond_Always;
6951 }
6952 
6954 {
6955  ImGuiContext& g = *GImGui;
6957  g.NextWindowData.SizeCond = cond ? cond : ImGuiCond_Always;
6958 }
6959 
6960 void ImGui::SetNextWindowSizeConstraints(const ImVec2& size_min, const ImVec2& size_max, ImGuiSizeCallback custom_callback, void* custom_callback_user_data)
6961 {
6962  ImGuiContext& g = *GImGui;
6964  g.NextWindowData.SizeConstraintRect = ImRect(size_min, size_max);
6965  g.NextWindowData.SizeCallback = custom_callback;
6966  g.NextWindowData.SizeCallbackUserData = custom_callback_user_data;
6967 }
6968 
6970 {
6971  ImGuiContext& g = *GImGui;
6972  g.NextWindowData.ContentSizeVal = size; // In Begin() we will add the size of window decorations (title bar, menu etc.) to that to form a SizeContents value.
6973  g.NextWindowData.ContentSizeCond = ImGuiCond_Always;
6974 }
6975 
6976 void ImGui::SetNextWindowCollapsed(bool collapsed, ImGuiCond cond)
6977 {
6978  ImGuiContext& g = *GImGui;
6979  g.NextWindowData.CollapsedVal = collapsed;
6980  g.NextWindowData.CollapsedCond = cond ? cond : ImGuiCond_Always;
6981 }
6982 
6984 {
6985  ImGuiContext& g = *GImGui;
6986  g.NextWindowData.FocusCond = ImGuiCond_Always; // Using a Cond member for consistency (may transition all of them to single flag set for fast Clear() op)
6987 }
6988 
6990 {
6991  ImGuiContext& g = *GImGui;
6993  g.NextWindowData.BgAlphaCond = ImGuiCond_Always; // Using a Cond member for consistency (may transition all of them to single flag set for fast Clear() op)
6994 }
6995 
6996 // In window space (not screen space!)
6998 {
6999  ImGuiWindow* window = GetCurrentWindowRead();
7000  ImVec2 mx = window->ContentsRegionRect.Max;
7001  if (window->DC.ColumnsSet)
7002  mx.x = GetColumnOffset(window->DC.ColumnsSet->Current + 1) - window->WindowPadding.x;
7003  return mx;
7004 }
7005 
7007 {
7008  ImGuiWindow* window = GetCurrentWindowRead();
7009  return GetContentRegionMax() - (window->DC.CursorPos - window->Pos);
7010 }
7011 
7013 {
7014  return GetContentRegionAvail().x;
7015 }
7016 
7017 // In window space (not screen space!)
7019 {
7020  ImGuiWindow* window = GetCurrentWindowRead();
7021  return window->ContentsRegionRect.Min;
7022 }
7023 
7025 {
7026  ImGuiWindow* window = GetCurrentWindowRead();
7027  return window->ContentsRegionRect.Max;
7028 }
7029 
7031 {
7032  ImGuiWindow* window = GetCurrentWindowRead();
7033  return window->ContentsRegionRect.Max.x - window->ContentsRegionRect.Min.x;
7034 }
7035 
7037 {
7038  ImGuiContext& g = *GImGui;
7039  return g.FontSize;
7040 }
7041 
7043 {
7044  ImGuiContext& g = *GImGui;
7045  return g.FontSize + g.Style.ItemSpacing.y;
7046 }
7047 
7049 {
7050  ImGuiContext& g = *GImGui;
7051  return g.FontSize + g.Style.FramePadding.y * 2.0f;
7052 }
7053 
7055 {
7056  ImGuiContext& g = *GImGui;
7057  return g.FontSize + g.Style.FramePadding.y * 2.0f + g.Style.ItemSpacing.y;
7058 }
7059 
7061 {
7062  ImGuiWindow* window = GetCurrentWindow();
7063  return window->DrawList;
7064 }
7065 
7067 {
7068  return GImGui->Font;
7069 }
7070 
7072 {
7073  return GImGui->FontSize;
7074 }
7075 
7077 {
7079 }
7080 
7082 {
7083  ImGuiContext& g = *GImGui;
7084  ImGuiWindow* window = GetCurrentWindow();
7085  window->FontWindowScale = scale;
7086  g.FontSize = g.DrawListSharedData.FontSize = window->CalcFontSize();
7087 }
7088 
7089 // User generally sees positions in window coordinates. Internally we store CursorPos in absolute screen coordinates because it is more convenient.
7090 // Conversion happens as we pass the value to user, but it makes our naming convention confusing because GetCursorPos() == (DC.CursorPos - window.Pos). May want to rename 'DC.CursorPos'.
7092 {
7093  ImGuiWindow* window = GetCurrentWindowRead();
7094  return window->DC.CursorPos - window->Pos + window->Scroll;
7095 }
7096 
7098 {
7099  ImGuiWindow* window = GetCurrentWindowRead();
7100  return window->DC.CursorPos.x - window->Pos.x + window->Scroll.x;
7101 }
7102 
7104 {
7105  ImGuiWindow* window = GetCurrentWindowRead();
7106  return window->DC.CursorPos.y - window->Pos.y + window->Scroll.y;
7107 }
7108 
7109 void ImGui::SetCursorPos(const ImVec2& local_pos)
7110 {
7111  ImGuiWindow* window = GetCurrentWindow();
7112  window->DC.CursorPos = window->Pos - window->Scroll + local_pos;
7113  window->DC.CursorMaxPos = ImMax(window->DC.CursorMaxPos, window->DC.CursorPos);
7114 }
7115 
7117 {
7118  ImGuiWindow* window = GetCurrentWindow();
7119  window->DC.CursorPos.x = window->Pos.x - window->Scroll.x + x;
7120  window->DC.CursorMaxPos.x = ImMax(window->DC.CursorMaxPos.x, window->DC.CursorPos.x);
7121 }
7122 
7124 {
7125  ImGuiWindow* window = GetCurrentWindow();
7126  window->DC.CursorPos.y = window->Pos.y - window->Scroll.y + y;
7127  window->DC.CursorMaxPos.y = ImMax(window->DC.CursorMaxPos.y, window->DC.CursorPos.y);
7128 }
7129 
7131 {
7132  ImGuiWindow* window = GetCurrentWindowRead();
7133  return window->DC.CursorStartPos - window->Pos;
7134 }
7135 
7137 {
7138  ImGuiWindow* window = GetCurrentWindowRead();
7139  return window->DC.CursorPos;
7140 }
7141 
7142 void ImGui::SetCursorScreenPos(const ImVec2& screen_pos)
7143 {
7144  ImGuiWindow* window = GetCurrentWindow();
7145  window->DC.CursorPos = screen_pos;
7146  window->DC.CursorMaxPos = ImMax(window->DC.CursorMaxPos, window->DC.CursorPos);
7147 }
7148 
7150 {
7151  return GImGui->CurrentWindow->Scroll.x;
7152 }
7153 
7155 {
7156  return GImGui->CurrentWindow->Scroll.y;
7157 }
7158 
7160 {
7162 }
7163 
7165 {
7167 }
7168 
7169 void ImGui::SetScrollX(float scroll_x)
7170 {
7171  ImGuiWindow* window = GetCurrentWindow();
7172  window->ScrollTarget.x = scroll_x;
7173  window->ScrollTargetCenterRatio.x = 0.0f;
7174 }
7175 
7176 void ImGui::SetScrollY(float scroll_y)
7177 {
7178  ImGuiWindow* window = GetCurrentWindow();
7179  window->ScrollTarget.y = scroll_y + window->TitleBarHeight() + window->MenuBarHeight(); // title bar height canceled out when using ScrollTargetRelY
7180  window->ScrollTargetCenterRatio.y = 0.0f;
7181 }
7182 
7183 void ImGui::SetScrollFromPosY(float pos_y, float center_y_ratio)
7184 {
7185  // We store a target position so centering can occur on the next frame when we are guaranteed to have a known window size
7186  ImGuiWindow* window = GetCurrentWindow();
7187  IM_ASSERT(center_y_ratio >= 0.0f && center_y_ratio <= 1.0f);
7188  window->ScrollTarget.y = (float)(int)(pos_y + window->Scroll.y);
7189  window->ScrollTargetCenterRatio.y = center_y_ratio;
7190 
7191  // Minor hack to to make scrolling to top/bottom of window take account of WindowPadding, it looks more right to the user this way
7192  if (center_y_ratio <= 0.0f && window->ScrollTarget.y <= window->WindowPadding.y)
7193  window->ScrollTarget.y = 0.0f;
7194  else if (center_y_ratio >= 1.0f && window->ScrollTarget.y >= window->SizeContents.y - window->WindowPadding.y + GImGui->Style.ItemSpacing.y)
7195  window->ScrollTarget.y = window->SizeContents.y;
7196 }
7197 
7198 // center_y_ratio: 0.0f top of last item, 0.5f vertical center of last item, 1.0f bottom of last item.
7199 void ImGui::SetScrollHere(float center_y_ratio)
7200 {
7201  ImGuiWindow* window = GetCurrentWindow();
7202  float target_y = window->DC.CursorPosPrevLine.y - window->Pos.y; // Top of last item, in window space
7203  target_y += (window->DC.PrevLineHeight * center_y_ratio) + (GImGui->Style.ItemSpacing.y * (center_y_ratio - 0.5f) * 2.0f); // Precisely aim above, in the middle or below the last line.
7204  SetScrollFromPosY(target_y, center_y_ratio);
7205 }
7206 
7208 {
7209  ImGuiContext& g = *GImGui;
7211 }
7212 
7214 {
7215  IM_ASSERT(offset >= -1); // -1 is allowed but not below
7216  ImGuiWindow* window = GetCurrentWindow();
7217  window->FocusIdxAllRequestNext = window->FocusIdxAllCounter + 1 + offset;
7218  window->FocusIdxTabRequestNext = INT_MAX;
7219 }
7220 
7222 {
7223  ImGuiContext& g = *GImGui;
7224  ImGuiWindow* window = g.CurrentWindow;
7225  if (!window->Appearing)
7226  return;
7227  if (g.NavWindow == window->RootWindowForNav && (g.NavInitRequest || g.NavInitResultId != 0) && g.NavLayer == g.NavWindow->DC.NavLayerCurrent)
7228  {
7229  g.NavInitRequest = false;
7230  g.NavInitResultId = g.NavWindow->DC.LastItemId;
7231  g.NavInitResultRectRel = ImRect(g.NavWindow->DC.LastItemRect.Min - g.NavWindow->Pos, g.NavWindow->DC.LastItemRect.Max - g.NavWindow->Pos);
7233  if (!IsItemVisible())
7234  SetScrollHere();
7235  }
7236 }
7237 
7239 {
7240  ImGuiWindow* window = GetCurrentWindow();
7241  window->DC.StateStorage = tree ? tree : &window->StateStorage;
7242 }
7243 
7245 {
7246  ImGuiWindow* window = GetCurrentWindowRead();
7247  return window->DC.StateStorage;
7248 }
7249 
7250 void ImGui::TextV(const char* fmt, va_list args)
7251 {
7252  ImGuiWindow* window = GetCurrentWindow();
7253  if (window->SkipItems)
7254  return;
7255 
7256  ImGuiContext& g = *GImGui;
7257  const char* text_end = g.TempBuffer + ImFormatStringV(g.TempBuffer, IM_ARRAYSIZE(g.TempBuffer), fmt, args);
7258  TextUnformatted(g.TempBuffer, text_end);
7259 }
7260 
7261 void ImGui::Text(const char* fmt, ...)
7262 {
7263  va_list args;
7264  va_start(args, fmt);
7265  TextV(fmt, args);
7266  va_end(args);
7267 }
7268 
7269 void ImGui::TextColoredV(const ImVec4& col, const char* fmt, va_list args)
7270 {
7272  TextV(fmt, args);
7273  PopStyleColor();
7274 }
7275 
7276 void ImGui::TextColored(const ImVec4& col, const char* fmt, ...)
7277 {
7278  va_list args;
7279  va_start(args, fmt);
7280  TextColoredV(col, fmt, args);
7281  va_end(args);
7282 }
7283 
7284 void ImGui::TextDisabledV(const char* fmt, va_list args)
7285 {
7287  TextV(fmt, args);
7288  PopStyleColor();
7289 }
7290 
7291 void ImGui::TextDisabled(const char* fmt, ...)
7292 {
7293  va_list args;
7294  va_start(args, fmt);
7295  TextDisabledV(fmt, args);
7296  va_end(args);
7297 }
7298 
7299 void ImGui::TextWrappedV(const char* fmt, va_list args)
7300 {
7301  bool need_wrap = (GImGui->CurrentWindow->DC.TextWrapPos < 0.0f); // Keep existing wrap position is one ia already set
7302  if (need_wrap) PushTextWrapPos(0.0f);
7303  TextV(fmt, args);
7304  if (need_wrap) PopTextWrapPos();
7305 }
7306 
7307 void ImGui::TextWrapped(const char* fmt, ...)
7308 {
7309  va_list args;
7310  va_start(args, fmt);
7311  TextWrappedV(fmt, args);
7312  va_end(args);
7313 }
7314 
7315 void ImGui::TextUnformatted(const char* text, const char* text_end)
7316 {
7317  ImGuiWindow* window = GetCurrentWindow();
7318  if (window->SkipItems)
7319  return;
7320 
7321  ImGuiContext& g = *GImGui;
7322  IM_ASSERT(text != NULL);
7323  const char* text_begin = text;
7324  if (text_end == NULL)
7325  text_end = text + strlen(text); // FIXME-OPT
7326 
7327  const ImVec2 text_pos(window->DC.CursorPos.x, window->DC.CursorPos.y + window->DC.CurrentLineTextBaseOffset);
7328  const float wrap_pos_x = window->DC.TextWrapPos;
7329  const bool wrap_enabled = wrap_pos_x >= 0.0f;
7330  if (text_end - text > 2000 && !wrap_enabled)
7331  {
7332  // Long text!
7333  // Perform manual coarse clipping to optimize for long multi-line text
7334  // From this point we will only compute the width of lines that are visible. Optimization only available when word-wrapping is disabled.
7335  // We also don't vertically center the text within the line full height, which is unlikely to matter because we are likely the biggest and only item on the line.
7336  const char* line = text;
7337  const float line_height = GetTextLineHeight();
7338  const ImRect clip_rect = window->ClipRect;
7339  ImVec2 text_size(0,0);
7340 
7341  if (text_pos.y <= clip_rect.Max.y)
7342  {
7343  ImVec2 pos = text_pos;
7344 
7345  // Lines to skip (can't skip when logging text)
7346  if (!g.LogEnabled)
7347  {
7348  int lines_skippable = (int)((clip_rect.Min.y - text_pos.y) / line_height);
7349  if (lines_skippable > 0)
7350  {
7351  int lines_skipped = 0;
7352  while (line < text_end && lines_skipped < lines_skippable)
7353  {
7354  const char* line_end = strchr(line, '\n');
7355  if (!line_end)
7356  line_end = text_end;
7357  line = line_end + 1;
7358  lines_skipped++;
7359  }
7360  pos.y += lines_skipped * line_height;
7361  }
7362  }
7363 
7364  // Lines to render
7365  if (line < text_end)
7366  {
7367  ImRect line_rect(pos, pos + ImVec2(FLT_MAX, line_height));
7368  while (line < text_end)
7369  {
7370  const char* line_end = strchr(line, '\n');
7371  if (IsClippedEx(line_rect, 0, false))
7372  break;
7373 
7374  const ImVec2 line_size = CalcTextSize(line, line_end, false);
7375  text_size.x = ImMax(text_size.x, line_size.x);
7376  RenderText(pos, line, line_end, false);
7377  if (!line_end)
7378  line_end = text_end;
7379  line = line_end + 1;
7380  line_rect.Min.y += line_height;
7381  line_rect.Max.y += line_height;
7382  pos.y += line_height;
7383  }
7384 
7385  // Count remaining lines
7386  int lines_skipped = 0;
7387  while (line < text_end)
7388  {
7389  const char* line_end = strchr(line, '\n');
7390  if (!line_end)
7391  line_end = text_end;
7392  line = line_end + 1;
7393  lines_skipped++;
7394  }
7395  pos.y += lines_skipped * line_height;
7396  }
7397 
7398  text_size.y += (pos - text_pos).y;
7399  }
7400 
7401  ImRect bb(text_pos, text_pos + text_size);
7402  ItemSize(bb);
7403  ItemAdd(bb, 0);
7404  }
7405  else
7406  {
7407  const float wrap_width = wrap_enabled ? CalcWrapWidthForPos(window->DC.CursorPos, wrap_pos_x) : 0.0f;
7408  const ImVec2 text_size = CalcTextSize(text_begin, text_end, false, wrap_width);
7409 
7410  // Account of baseline offset
7411  ImRect bb(text_pos, text_pos + text_size);
7412  ItemSize(text_size);
7413  if (!ItemAdd(bb, 0))
7414  return;
7415 
7416  // Render (we don't hide text after ## in this end-user function)
7417  RenderTextWrapped(bb.Min, text_begin, text_end, wrap_width);
7418  }
7419 }
7420 
7422 {
7423  ImGuiWindow* window = GetCurrentWindow();
7424  if (window->SkipItems)
7425  return;
7426 
7427  ImGuiContext& g = *GImGui;
7428  window->DC.CurrentLineHeight = ImMax(window->DC.CurrentLineHeight, g.FontSize + g.Style.FramePadding.y * 2);
7429  window->DC.CurrentLineTextBaseOffset = ImMax(window->DC.CurrentLineTextBaseOffset, g.Style.FramePadding.y);
7430 }
7431 
7432 // Add a label+text combo aligned to other label+value widgets
7433 void ImGui::LabelTextV(const char* label, const char* fmt, va_list args)
7434 {
7435  ImGuiWindow* window = GetCurrentWindow();
7436  if (window->SkipItems)
7437  return;
7438 
7439  ImGuiContext& g = *GImGui;
7440  const ImGuiStyle& style = g.Style;
7441  const float w = CalcItemWidth();
7442 
7443  const ImVec2 label_size = CalcTextSize(label, NULL, true);
7444  const ImRect value_bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(w, label_size.y + style.FramePadding.y*2));
7445  const ImRect total_bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(w + (label_size.x > 0.0f ? style.ItemInnerSpacing.x : 0.0f), style.FramePadding.y*2) + label_size);
7446  ItemSize(total_bb, style.FramePadding.y);
7447  if (!ItemAdd(total_bb, 0))
7448  return;
7449 
7450  // Render
7451  const char* value_text_begin = &g.TempBuffer[0];
7452  const char* value_text_end = value_text_begin + ImFormatStringV(g.TempBuffer, IM_ARRAYSIZE(g.TempBuffer), fmt, args);
7453  RenderTextClipped(value_bb.Min, value_bb.Max, value_text_begin, value_text_end, NULL, ImVec2(0.0f,0.5f));
7454  if (label_size.x > 0.0f)
7455  RenderText(ImVec2(value_bb.Max.x + style.ItemInnerSpacing.x, value_bb.Min.y + style.FramePadding.y), label);
7456 }
7457 
7458 void ImGui::LabelText(const char* label, const char* fmt, ...)
7459 {
7460  va_list args;
7461  va_start(args, fmt);
7462  LabelTextV(label, fmt, args);
7463  va_end(args);
7464 }
7465 
7466 bool ImGui::ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool* out_held, ImGuiButtonFlags flags)
7467 {
7468  ImGuiContext& g = *GImGui;
7469  ImGuiWindow* window = GetCurrentWindow();
7470 
7472  {
7473  if (out_hovered) *out_hovered = false;
7474  if (out_held) *out_held = false;
7475  if (g.ActiveId == id) ClearActiveID();
7476  return false;
7477  }
7478 
7479  // Default behavior requires click+release on same spot
7482 
7483  ImGuiWindow* backup_hovered_window = g.HoveredWindow;
7484  if ((flags & ImGuiButtonFlags_FlattenChildren) && g.HoveredRootWindow == window)
7485  g.HoveredWindow = window;
7486 
7487  bool pressed = false;
7488  bool hovered = ItemHoverable(bb, id);
7489 
7490  // Special mode for Drag and Drop where holding button pressed for a long time while dragging another item triggers the button
7491  if ((flags & ImGuiButtonFlags_PressedOnDragDropHold) && g.DragDropActive && !(g.DragDropSourceFlags & ImGuiDragDropFlags_SourceNoHoldToOpenOthers))
7493  {
7494  hovered = true;
7495  SetHoveredID(id);
7496  if (CalcTypematicPressedRepeatAmount(g.HoveredIdTimer + 0.0001f, g.HoveredIdTimer + 0.0001f - g.IO.DeltaTime, 0.01f, 0.70f)) // FIXME: Our formula for CalcTypematicPressedRepeatAmount() is fishy
7497  {
7498  pressed = true;
7499  FocusWindow(window);
7500  }
7501  }
7502 
7503  if ((flags & ImGuiButtonFlags_FlattenChildren) && g.HoveredRootWindow == window)
7504  g.HoveredWindow = backup_hovered_window;
7505 
7506  // AllowOverlap mode (rarely used) requires previous frame HoveredId to be null or to match. This allows using patterns where a later submitted widget overlaps a previous one.
7507  if (hovered && (flags & ImGuiButtonFlags_AllowItemOverlap) && (g.HoveredIdPreviousFrame != id && g.HoveredIdPreviousFrame != 0))
7508  hovered = false;
7509 
7510  // Mouse
7511  if (hovered)
7512  {
7513  if (!(flags & ImGuiButtonFlags_NoKeyModifiers) || (!g.IO.KeyCtrl && !g.IO.KeyShift && !g.IO.KeyAlt))
7514  {
7515  // | CLICKING | HOLDING with ImGuiButtonFlags_Repeat
7516  // PressedOnClickRelease | <on release>* | <on repeat> <on repeat> .. (NOT on release) <-- MOST COMMON! (*) only if both click/release were over bounds
7517  // PressedOnClick | <on click> | <on click> <on repeat> <on repeat> ..
7518  // PressedOnRelease | <on release> | <on repeat> <on repeat> .. (NOT on release)
7519  // PressedOnDoubleClick | <on dclick> | <on dclick> <on repeat> <on repeat> ..
7520  // FIXME-NAV: We don't honor those different behaviors.
7521  if ((flags & ImGuiButtonFlags_PressedOnClickRelease) && g.IO.MouseClicked[0])
7522  {
7523  SetActiveID(id, window);
7525  SetFocusID(id, window);
7526  FocusWindow(window);
7527  }
7528  if (((flags & ImGuiButtonFlags_PressedOnClick) && g.IO.MouseClicked[0]) || ((flags & ImGuiButtonFlags_PressedOnDoubleClick) && g.IO.MouseDoubleClicked[0]))
7529  {
7530  pressed = true;
7532  ClearActiveID();
7533  else
7534  SetActiveID(id, window); // Hold on ID
7535  FocusWindow(window);
7536  }
7537  if ((flags & ImGuiButtonFlags_PressedOnRelease) && g.IO.MouseReleased[0])
7538  {
7539  if (!((flags & ImGuiButtonFlags_Repeat) && g.IO.MouseDownDurationPrev[0] >= g.IO.KeyRepeatDelay)) // Repeat mode trumps <on release>
7540  pressed = true;
7541  ClearActiveID();
7542  }
7543 
7544  // 'Repeat' mode acts when held regardless of _PressedOn flags (see table above).
7545  // Relies on repeat logic of IsMouseClicked() but we may as well do it ourselves if we end up exposing finer RepeatDelay/RepeatRate settings.
7546  if ((flags & ImGuiButtonFlags_Repeat) && g.ActiveId == id && g.IO.MouseDownDuration[0] > 0.0f && IsMouseClicked(0, true))
7547  pressed = true;
7548  }
7549 
7550  if (pressed)
7551  g.NavDisableHighlight = true;
7552  }
7553 
7554  // Gamepad/Keyboard navigation
7555  // We report navigated item as hovered but we don't set g.HoveredId to not interfere with mouse.
7556  if (g.NavId == id && !g.NavDisableHighlight && g.NavDisableMouseHover && (g.ActiveId == 0 || g.ActiveId == id || g.ActiveId == window->MoveId))
7557  hovered = true;
7558 
7559  if (g.NavActivateDownId == id)
7560  {
7561  bool nav_activated_by_code = (g.NavActivateId == id);
7563  if (nav_activated_by_code || nav_activated_by_inputs)
7564  pressed = true;
7565  if (nav_activated_by_code || nav_activated_by_inputs || g.ActiveId == id)
7566  {
7567  // Set active id so it can be queried by user via IsItemActive(), equivalent of holding the mouse button.
7568  g.NavActivateId = id; // This is so SetActiveId assign a Nav source
7569  SetActiveID(id, window);
7571  SetFocusID(id, window);
7572  g.ActiveIdAllowNavDirFlags = (1 << ImGuiDir_Left) | (1 << ImGuiDir_Right) | (1 << ImGuiDir_Up) | (1 << ImGuiDir_Down);
7573  }
7574  }
7575 
7576  bool held = false;
7577  if (g.ActiveId == id)
7578  {
7579  if (g.ActiveIdSource == ImGuiInputSource_Mouse)
7580  {
7581  if (g.ActiveIdIsJustActivated)
7582  g.ActiveIdClickOffset = g.IO.MousePos - bb.Min;
7583  if (g.IO.MouseDown[0])
7584  {
7585  held = true;
7586  }
7587  else
7588  {
7589  if (hovered && (flags & ImGuiButtonFlags_PressedOnClickRelease))
7590  if (!((flags & ImGuiButtonFlags_Repeat) && g.IO.MouseDownDurationPrev[0] >= g.IO.KeyRepeatDelay)) // Repeat mode trumps <on release>
7591  if (!g.DragDropActive)
7592  pressed = true;
7593  ClearActiveID();
7594  }
7596  g.NavDisableHighlight = true;
7597  }
7598  else if (g.ActiveIdSource == ImGuiInputSource_Nav)
7599  {
7600  if (g.NavActivateDownId != id)
7601  ClearActiveID();
7602  }
7603  }
7604 
7605  if (out_hovered) *out_hovered = hovered;
7606  if (out_held) *out_held = held;
7607 
7608  return pressed;
7609 }
7610 
7611 bool ImGui::ButtonEx(const char* label, const ImVec2& size_arg, ImGuiButtonFlags flags)
7612 {
7613  ImGuiWindow* window = GetCurrentWindow();
7614  if (window->SkipItems)
7615  return false;
7616 
7617  ImGuiContext& g = *GImGui;
7618  const ImGuiStyle& style = g.Style;
7619  const ImGuiID id = window->GetID(label);
7620  const ImVec2 label_size = CalcTextSize(label, NULL, true);
7621 
7622  ImVec2 pos = window->DC.CursorPos;
7623  if ((flags & ImGuiButtonFlags_AlignTextBaseLine) && style.FramePadding.y < window->DC.CurrentLineTextBaseOffset) // Try to vertically align buttons that are smaller/have no padding so that text baseline matches (bit hacky, since it shouldn't be a flag)
7624  pos.y += window->DC.CurrentLineTextBaseOffset - style.FramePadding.y;
7625  ImVec2 size = CalcItemSize(size_arg, label_size.x + style.FramePadding.x * 2.0f, label_size.y + style.FramePadding.y * 2.0f);
7626 
7627  const ImRect bb(pos, pos + size);
7628  ItemSize(bb, style.FramePadding.y);
7629  if (!ItemAdd(bb, id))
7630  return false;
7631 
7634  bool hovered, held;
7635  bool pressed = ButtonBehavior(bb, id, &hovered, &held, flags);
7636 
7637  // Render
7638  const ImU32 col = GetColorU32((hovered && held) ? ImGuiCol_ButtonActive : hovered ? ImGuiCol_ButtonHovered : ImGuiCol_Button);
7639  RenderNavHighlight(bb, id);
7640  RenderFrame(bb.Min, bb.Max, col, true, style.FrameRounding);
7641  RenderTextClipped(bb.Min + style.FramePadding, bb.Max - style.FramePadding, label, NULL, &label_size, style.ButtonTextAlign, &bb);
7642 
7643  // Automatically close popups
7644  //if (pressed && !(flags & ImGuiButtonFlags_DontClosePopups) && (window->Flags & ImGuiWindowFlags_Popup))
7645  // CloseCurrentPopup();
7646 
7647  return pressed;
7648 }
7649 
7650 bool ImGui::Button(const char* label, const ImVec2& size_arg)
7651 {
7652  return ButtonEx(label, size_arg, 0);
7653 }
7654 
7655 // Small buttons fits within text without additional vertical spacing.
7656 bool ImGui::SmallButton(const char* label)
7657 {
7658  ImGuiContext& g = *GImGui;
7659  float backup_padding_y = g.Style.FramePadding.y;
7660  g.Style.FramePadding.y = 0.0f;
7662  g.Style.FramePadding.y = backup_padding_y;
7663  return pressed;
7664 }
7665 
7666 // Tip: use ImGui::PushID()/PopID() to push indices or pointers in the ID stack.
7667 // Then you can keep 'str_id' empty or the same for all your buttons (instead of creating a string based on a non-string id)
7668 bool ImGui::InvisibleButton(const char* str_id, const ImVec2& size_arg)
7669 {
7670  ImGuiWindow* window = GetCurrentWindow();
7671  if (window->SkipItems)
7672  return false;
7673 
7674  const ImGuiID id = window->GetID(str_id);
7675  ImVec2 size = CalcItemSize(size_arg, 0.0f, 0.0f);
7676  const ImRect bb(window->DC.CursorPos, window->DC.CursorPos + size);
7677  ItemSize(bb);
7678  if (!ItemAdd(bb, id))
7679  return false;
7680 
7681  bool hovered, held;
7682  bool pressed = ButtonBehavior(bb, id, &hovered, &held);
7683 
7684  return pressed;
7685 }
7686 
7687 // Button to close a window
7688 bool ImGui::CloseButton(ImGuiID id, const ImVec2& pos, float radius)
7689 {
7690  ImGuiContext& g = *GImGui;
7691  ImGuiWindow* window = g.CurrentWindow;
7692 
7693  // We intentionally allow interaction when clipped so that a mechanical Alt,Right,Validate sequence close a window.
7694  // (this isn't the regular behavior of buttons, but it doesn't affect the user much because navigation tends to keep items visible).
7695  const ImRect bb(pos - ImVec2(radius,radius), pos + ImVec2(radius,radius));
7696  bool is_clipped = !ItemAdd(bb, id);
7697 
7698  bool hovered, held;
7699  bool pressed = ButtonBehavior(bb, id, &hovered, &held);
7700  if (is_clipped)
7701  return pressed;
7702 
7703  // Render
7704  const ImU32 col = GetColorU32((held && hovered) ? ImGuiCol_CloseButtonActive : hovered ? ImGuiCol_CloseButtonHovered : ImGuiCol_CloseButton);
7705  ImVec2 center = bb.GetCenter();
7706  window->DrawList->AddCircleFilled(center, ImMax(2.0f, radius), col, 12);
7707 
7708  const float cross_extent = (radius * 0.7071f) - 1.0f;
7709  if (hovered)
7710  {
7711  center -= ImVec2(0.5f, 0.5f);
7712  window->DrawList->AddLine(center + ImVec2(+cross_extent,+cross_extent), center + ImVec2(-cross_extent,-cross_extent), GetColorU32(ImGuiCol_Text));
7713  window->DrawList->AddLine(center + ImVec2(+cross_extent,-cross_extent), center + ImVec2(-cross_extent,+cross_extent), GetColorU32(ImGuiCol_Text));
7714  }
7715  return pressed;
7716 }
7717 
7718 // [Internal]
7720 {
7721  ImGuiContext& g = *GImGui;
7722  ImGuiWindow* window = g.CurrentWindow;
7723  if (window->SkipItems)
7724  return false;
7725 
7726  const ImGuiStyle& style = g.Style;
7727 
7728  const ImRect bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(g.FontSize + padding.x * 2.0f, g.FontSize + padding.y * 2.0f));
7729  ItemSize(bb, style.FramePadding.y);
7730  if (!ItemAdd(bb, id))
7731  return false;
7732 
7733  bool hovered, held;
7734  bool pressed = ButtonBehavior(bb, id, &hovered, &held, flags);
7735 
7736  const ImU32 col = GetColorU32((hovered && held) ? ImGuiCol_ButtonActive : hovered ? ImGuiCol_ButtonHovered : ImGuiCol_Button);
7737  RenderNavHighlight(bb, id);
7738  RenderFrame(bb.Min, bb.Max, col, true, style.FrameRounding);
7739  RenderTriangle(bb.Min + padding, dir, 1.0f);
7740 
7741  return pressed;
7742 }
7743 
7744 void ImGui::Image(ImTextureID user_texture_id, const ImVec2& size, const ImVec2& uv0, const ImVec2& uv1, const ImVec4& tint_col, const ImVec4& border_col)
7745 {
7746  ImGuiWindow* window = GetCurrentWindow();
7747  if (window->SkipItems)
7748  return;
7749 
7750  ImRect bb(window->DC.CursorPos, window->DC.CursorPos + size);
7751  if (border_col.w > 0.0f)
7752  bb.Max += ImVec2(2,2);
7753  ItemSize(bb);
7754  if (!ItemAdd(bb, 0))
7755  return;
7756 
7757  if (border_col.w > 0.0f)
7758  {
7759  window->DrawList->AddRect(bb.Min, bb.Max, GetColorU32(border_col), 0.0f);
7760  window->DrawList->AddImage(user_texture_id, bb.Min+ImVec2(1,1), bb.Max-ImVec2(1,1), uv0, uv1, GetColorU32(tint_col));
7761  }
7762  else
7763  {
7764  window->DrawList->AddImage(user_texture_id, bb.Min, bb.Max, uv0, uv1, GetColorU32(tint_col));
7765  }
7766 }
7767 
7768 // frame_padding < 0: uses FramePadding from style (default)
7769 // frame_padding = 0: no framing
7770 // frame_padding > 0: set framing size
7771 // The color used are the button colors.
7772 bool ImGui::ImageButton(ImTextureID user_texture_id, const ImVec2& size, const ImVec2& uv0, const ImVec2& uv1, int frame_padding, const ImVec4& bg_col, const ImVec4& tint_col)
7773 {
7774  ImGuiWindow* window = GetCurrentWindow();
7775  if (window->SkipItems)
7776  return false;
7777 
7778  ImGuiContext& g = *GImGui;
7779  const ImGuiStyle& style = g.Style;
7780 
7781  // Default to using texture ID as ID. User can still push string/integer prefixes.
7782  // We could hash the size/uv to create a unique ID but that would prevent the user from animating UV.
7783  PushID((void *)user_texture_id);
7784  const ImGuiID id = window->GetID("#image");
7785  PopID();
7786 
7787  const ImVec2 padding = (frame_padding >= 0) ? ImVec2((float)frame_padding, (float)frame_padding) : style.FramePadding;
7788  const ImRect bb(window->DC.CursorPos, window->DC.CursorPos + size + padding*2);
7789  const ImRect image_bb(window->DC.CursorPos + padding, window->DC.CursorPos + padding + size);
7790  ItemSize(bb);
7791  if (!ItemAdd(bb, id))
7792  return false;
7793 
7794  bool hovered, held;
7795  bool pressed = ButtonBehavior(bb, id, &hovered, &held);
7796 
7797  // Render
7798  const ImU32 col = GetColorU32((hovered && held) ? ImGuiCol_ButtonActive : hovered ? ImGuiCol_ButtonHovered : ImGuiCol_Button);
7799  RenderNavHighlight(bb, id);
7800  RenderFrame(bb.Min, bb.Max, col, true, ImClamp((float)ImMin(padding.x, padding.y), 0.0f, style.FrameRounding));
7801  if (bg_col.w > 0.0f)
7802  window->DrawList->AddRectFilled(image_bb.Min, image_bb.Max, GetColorU32(bg_col));
7803  window->DrawList->AddImage(user_texture_id, image_bb.Min, image_bb.Max, uv0, uv1, GetColorU32(tint_col));
7804 
7805  return pressed;
7806 }
7807 
7808 // Start logging ImGui output to TTY
7809 void ImGui::LogToTTY(int max_depth)
7810 {
7811  ImGuiContext& g = *GImGui;
7812  if (g.LogEnabled)
7813  return;
7814  ImGuiWindow* window = g.CurrentWindow;
7815 
7816  IM_ASSERT(g.LogFile == NULL);
7817  g.LogFile = stdout;
7818  g.LogEnabled = true;
7819  g.LogStartDepth = window->DC.TreeDepth;
7820  if (max_depth >= 0)
7821  g.LogAutoExpandMaxDepth = max_depth;
7822 }
7823 
7824 // Start logging ImGui output to given file
7825 void ImGui::LogToFile(int max_depth, const char* filename)
7826 {
7827  ImGuiContext& g = *GImGui;
7828  if (g.LogEnabled)
7829  return;
7830  ImGuiWindow* window = g.CurrentWindow;
7831 
7832  if (!filename)
7833  {
7834  filename = g.IO.LogFilename;
7835  if (!filename)
7836  return;
7837  }
7838 
7839  IM_ASSERT(g.LogFile == NULL);
7840  g.LogFile = ImFileOpen(filename, "ab");
7841  if (!g.LogFile)
7842  {
7843  IM_ASSERT(g.LogFile != NULL); // Consider this an error
7844  return;
7845  }
7846  g.LogEnabled = true;
7847  g.LogStartDepth = window->DC.TreeDepth;
7848  if (max_depth >= 0)
7849  g.LogAutoExpandMaxDepth = max_depth;
7850 }
7851 
7852 // Start logging ImGui output to clipboard
7853 void ImGui::LogToClipboard(int max_depth)
7854 {
7855  ImGuiContext& g = *GImGui;
7856  if (g.LogEnabled)
7857  return;
7858  ImGuiWindow* window = g.CurrentWindow;
7859 
7860  IM_ASSERT(g.LogFile == NULL);
7861  g.LogFile = NULL;
7862  g.LogEnabled = true;
7863  g.LogStartDepth = window->DC.TreeDepth;
7864  if (max_depth >= 0)
7865  g.LogAutoExpandMaxDepth = max_depth;
7866 }
7867 
7869 {
7870  ImGuiContext& g = *GImGui;
7871  if (!g.LogEnabled)
7872  return;
7873 
7875  if (g.LogFile != NULL)
7876  {
7877  if (g.LogFile == stdout)
7878  fflush(g.LogFile);
7879  else
7880  fclose(g.LogFile);
7881  g.LogFile = NULL;
7882  }
7883  if (g.LogClipboard->size() > 1)
7884  {
7885  SetClipboardText(g.LogClipboard->begin());
7886  g.LogClipboard->clear();
7887  }
7888  g.LogEnabled = false;
7889 }
7890 
7891 // Helper to display logging buttons
7893 {
7894  ImGuiContext& g = *GImGui;
7895 
7896  PushID("LogButtons");
7897  const bool log_to_tty = Button("Log To TTY"); SameLine();
7898  const bool log_to_file = Button("Log To File"); SameLine();
7899  const bool log_to_clipboard = Button("Log To Clipboard"); SameLine();
7900  PushItemWidth(80.0f);
7901  PushAllowKeyboardFocus(false);
7902  SliderInt("Depth", &g.LogAutoExpandMaxDepth, 0, 9, NULL);
7904  PopItemWidth();
7905  PopID();
7906 
7907  // Start logging at the end of the function so that the buttons don't appear in the log
7908  if (log_to_tty)
7909  LogToTTY(g.LogAutoExpandMaxDepth);
7910  if (log_to_file)
7911  LogToFile(g.LogAutoExpandMaxDepth, g.IO.LogFilename);
7912  if (log_to_clipboard)
7913  LogToClipboard(g.LogAutoExpandMaxDepth);
7914 }
7915 
7917 {
7919  return true;
7920 
7921  // We only write to the tree storage if the user clicks (or explicitely use SetNextTreeNode*** functions)
7922  ImGuiContext& g = *GImGui;
7923  ImGuiWindow* window = g.CurrentWindow;
7924  ImGuiStorage* storage = window->DC.StateStorage;
7925 
7926  bool is_open;
7927  if (g.NextTreeNodeOpenCond != 0)
7928  {
7929  if (g.NextTreeNodeOpenCond & ImGuiCond_Always)
7930  {
7931  is_open = g.NextTreeNodeOpenVal;
7932  storage->SetInt(id, is_open);
7933  }
7934  else
7935  {
7936  // We treat ImGuiCond_Once and ImGuiCond_FirstUseEver the same because tree node state are not saved persistently.
7937  const int stored_value = storage->GetInt(id, -1);
7938  if (stored_value == -1)
7939  {
7940  is_open = g.NextTreeNodeOpenVal;
7941  storage->SetInt(id, is_open);
7942  }
7943  else
7944  {
7945  is_open = stored_value != 0;
7946  }
7947  }
7948  g.NextTreeNodeOpenCond = 0;
7949  }
7950  else
7951  {
7952  is_open = storage->GetInt(id, (flags & ImGuiTreeNodeFlags_DefaultOpen) ? 1 : 0) != 0;
7953  }
7954 
7955  // When logging is enabled, we automatically expand tree nodes (but *NOT* collapsing headers.. seems like sensible behavior).
7956  // NB- If we are above max depth we still allow manually opened nodes to be logged.
7957  if (g.LogEnabled && !(flags & ImGuiTreeNodeFlags_NoAutoOpenOnLog) && window->DC.TreeDepth < g.LogAutoExpandMaxDepth)
7958  is_open = true;
7959 
7960  return is_open;
7961 }
7962 
7963 bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* label, const char* label_end)
7964 {
7965  ImGuiWindow* window = GetCurrentWindow();
7966  if (window->SkipItems)
7967  return false;
7968 
7969  ImGuiContext& g = *GImGui;
7970  const ImGuiStyle& style = g.Style;
7971  const bool display_frame = (flags & ImGuiTreeNodeFlags_Framed) != 0;
7972  const ImVec2 padding = (display_frame || (flags & ImGuiTreeNodeFlags_FramePadding)) ? style.FramePadding : ImVec2(style.FramePadding.x, 0.0f);
7973 
7974  if (!label_end)
7975  label_end = FindRenderedTextEnd(label);
7976  const ImVec2 label_size = CalcTextSize(label, label_end, false);
7977 
7978  // We vertically grow up to current line height up the typical widget height.
7979  const float text_base_offset_y = ImMax(padding.y, window->DC.CurrentLineTextBaseOffset); // Latch before ItemSize changes it
7980  const float frame_height = ImMax(ImMin(window->DC.CurrentLineHeight, g.FontSize + style.FramePadding.y*2), label_size.y + padding.y*2);
7981  ImRect frame_bb = ImRect(window->DC.CursorPos, ImVec2(window->Pos.x + GetContentRegionMax().x, window->DC.CursorPos.y + frame_height));
7982  if (display_frame)
7983  {
7984  // Framed header expand a little outside the default padding
7985  frame_bb.Min.x -= (float)(int)(window->WindowPadding.x*0.5f) - 1;
7986  frame_bb.Max.x += (float)(int)(window->WindowPadding.x*0.5f) - 1;
7987  }
7988 
7989  const float text_offset_x = (g.FontSize + (display_frame ? padding.x*3 : padding.x*2)); // Collapser arrow width + Spacing
7990  const float text_width = g.FontSize + (label_size.x > 0.0f ? label_size.x + padding.x*2 : 0.0f); // Include collapser
7991  ItemSize(ImVec2(text_width, frame_height), text_base_offset_y);
7992 
7993  // For regular tree nodes, we arbitrary allow to click past 2 worth of ItemSpacing
7994  // (Ideally we'd want to add a flag for the user to specify if we want the hit test to be done up to the right side of the content or not)
7995  const ImRect interact_bb = display_frame ? frame_bb : ImRect(frame_bb.Min.x, frame_bb.Min.y, frame_bb.Min.x + text_width + style.ItemSpacing.x*2, frame_bb.Max.y);
7996  bool is_open = TreeNodeBehaviorIsOpen(id, flags);
7997 
7998  // Store a flag for the current depth to tell if we will allow closing this node when navigating one of its child.
7999  // For this purpose we essentially compare if g.NavIdIsAlive went from 0 to 1 between TreeNode() and TreePop().
8000  // This is currently only support 32 level deep and we are fine with (1 << Depth) overflowing into a zero.
8001  if (is_open && !g.NavIdIsAlive && (flags & ImGuiTreeNodeFlags_NavLeftJumpsBackHere) && !(flags & ImGuiTreeNodeFlags_NoTreePushOnOpen))
8002  window->DC.TreeDepthMayJumpToParentOnPop |= (1 << window->DC.TreeDepth);
8003 
8004  bool item_add = ItemAdd(interact_bb, id);
8006  window->DC.LastItemDisplayRect = frame_bb;
8007 
8008  if (!item_add)
8009  {
8010  if (is_open && !(flags & ImGuiTreeNodeFlags_NoTreePushOnOpen))
8011  TreePushRawID(id);
8012  return is_open;
8013  }
8014 
8015  // Flags that affects opening behavior:
8016  // - 0(default) ..................... single-click anywhere to open
8017  // - OpenOnDoubleClick .............. double-click anywhere to open
8018  // - OpenOnArrow .................... single-click on arrow to open
8019  // - OpenOnDoubleClick|OpenOnArrow .. single-click on arrow or double-click anywhere to open
8021  if (!(flags & ImGuiTreeNodeFlags_Leaf))
8025 
8026  bool hovered, held, pressed = ButtonBehavior(interact_bb, id, &hovered, &held, button_flags);
8027  if (!(flags & ImGuiTreeNodeFlags_Leaf))
8028  {
8029  bool toggled = false;
8030  if (pressed)
8031  {
8032  toggled = !(flags & (ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_OpenOnDoubleClick)) || (g.NavActivateId == id);
8034  toggled |= IsMouseHoveringRect(interact_bb.Min, ImVec2(interact_bb.Min.x + text_offset_x, interact_bb.Max.y)) && (!g.NavDisableMouseHover);
8036  toggled |= g.IO.MouseDoubleClicked[0];
8037  if (g.DragDropActive && is_open) // When using Drag and Drop "hold to open" we keep the node highlighted after opening, but never close it again.
8038  toggled = false;
8039  }
8040 
8041  if (g.NavId == id && g.NavMoveRequest && g.NavMoveDir == ImGuiDir_Left && is_open)
8042  {
8043  toggled = true;
8045  }
8046  if (g.NavId == id && g.NavMoveRequest && g.NavMoveDir == ImGuiDir_Right && !is_open) // If there's something upcoming on the line we may want to give it the priority?
8047  {
8048  toggled = true;
8050  }
8051 
8052  if (toggled)
8053  {
8054  is_open = !is_open;
8055  window->DC.StateStorage->SetInt(id, is_open);
8056  }
8057  }
8060 
8061  // Render
8062  const ImU32 col = GetColorU32((held && hovered) ? ImGuiCol_HeaderActive : hovered ? ImGuiCol_HeaderHovered : ImGuiCol_Header);
8063  const ImVec2 text_pos = frame_bb.Min + ImVec2(text_offset_x, text_base_offset_y);
8064  if (display_frame)
8065  {
8066  // Framed type
8067  RenderFrame(frame_bb.Min, frame_bb.Max, col, true, style.FrameRounding);
8069  RenderTriangle(frame_bb.Min + ImVec2(padding.x, text_base_offset_y), is_open ? ImGuiDir_Down : ImGuiDir_Right, 1.0f);
8070  if (g.LogEnabled)
8071  {
8072  // NB: '##' is normally used to hide text (as a library-wide feature), so we need to specify the text range to make sure the ## aren't stripped out here.
8073  const char log_prefix[] = "\n##";
8074  const char log_suffix[] = "##";
8075  LogRenderedText(&text_pos, log_prefix, log_prefix+3);
8076  RenderTextClipped(text_pos, frame_bb.Max, label, label_end, &label_size);
8077  LogRenderedText(&text_pos, log_suffix+1, log_suffix+3);
8078  }
8079  else
8080  {
8081  RenderTextClipped(text_pos, frame_bb.Max, label, label_end, &label_size);
8082  }
8083  }
8084  else
8085  {
8086  // Unframed typed for tree nodes
8087  if (hovered || (flags & ImGuiTreeNodeFlags_Selected))
8088  {
8089  RenderFrame(frame_bb.Min, frame_bb.Max, col, false);
8091  }
8092 
8094  RenderBullet(frame_bb.Min + ImVec2(text_offset_x * 0.5f, g.FontSize*0.50f + text_base_offset_y));
8095  else if (!(flags & ImGuiTreeNodeFlags_Leaf))
8096  RenderTriangle(frame_bb.Min + ImVec2(padding.x, g.FontSize*0.15f + text_base_offset_y), is_open ? ImGuiDir_Down : ImGuiDir_Right, 0.70f);
8097  if (g.LogEnabled)
8098  LogRenderedText(&text_pos, ">");
8099  RenderText(text_pos, label, label_end, false);
8100  }
8101 
8102  if (is_open && !(flags & ImGuiTreeNodeFlags_NoTreePushOnOpen))
8103  TreePushRawID(id);
8104  return is_open;
8105 }
8106 
8107 // CollapsingHeader returns true when opened but do not indent nor push into the ID stack (because of the ImGuiTreeNodeFlags_NoTreePushOnOpen flag).
8108 // This is basically the same as calling TreeNodeEx(label, ImGuiTreeNodeFlags_CollapsingHeader | ImGuiTreeNodeFlags_NoTreePushOnOpen). You can remove the _NoTreePushOnOpen flag if you want behavior closer to normal TreeNode().
8110 {
8111  ImGuiWindow* window = GetCurrentWindow();
8112  if (window->SkipItems)
8113  return false;
8114 
8116 }
8117 
8118 bool ImGui::CollapsingHeader(const char* label, bool* p_open, ImGuiTreeNodeFlags flags)
8119 {
8120  ImGuiWindow* window = GetCurrentWindow();
8121  if (window->SkipItems)
8122  return false;
8123 
8124  if (p_open && !*p_open)
8125  return false;
8126 
8127  ImGuiID id = window->GetID(label);
8129  if (p_open)
8130  {
8131  // Create a small overlapping close button // FIXME: We can evolve this into user accessible helpers to add extra buttons on title bars, headers, etc.
8132  ImGuiContext& g = *GImGui;
8133  float button_sz = g.FontSize * 0.5f;
8134  ImGuiItemHoveredDataBackup last_item_backup;
8135  if (CloseButton(window->GetID((void*)(intptr_t)(id+1)), ImVec2(ImMin(window->DC.LastItemRect.Max.x, window->ClipRect.Max.x) - g.Style.FramePadding.x - button_sz, window->DC.LastItemRect.Min.y + g.Style.FramePadding.y + button_sz), button_sz))
8136  *p_open = false;
8137  last_item_backup.Restore();
8138  }
8139 
8140  return is_open;
8141 }
8142 
8144 {
8145  ImGuiWindow* window = GetCurrentWindow();
8146  if (window->SkipItems)
8147  return false;
8148 
8149  return TreeNodeBehavior(window->GetID(label), flags, label, NULL);
8150 }
8151 
8152 bool ImGui::TreeNodeExV(const char* str_id, ImGuiTreeNodeFlags flags, const char* fmt, va_list args)
8153 {
8154  ImGuiWindow* window = GetCurrentWindow();
8155  if (window->SkipItems)
8156  return false;
8157 
8158  ImGuiContext& g = *GImGui;
8159  const char* label_end = g.TempBuffer + ImFormatStringV(g.TempBuffer, IM_ARRAYSIZE(g.TempBuffer), fmt, args);
8160  return TreeNodeBehavior(window->GetID(str_id), flags, g.TempBuffer, label_end);
8161 }
8162 
8163 bool ImGui::TreeNodeExV(const void* ptr_id, ImGuiTreeNodeFlags flags, const char* fmt, va_list args)
8164 {
8165  ImGuiWindow* window = GetCurrentWindow();
8166  if (window->SkipItems)
8167  return false;
8168 
8169  ImGuiContext& g = *GImGui;
8170  const char* label_end = g.TempBuffer + ImFormatStringV(g.TempBuffer, IM_ARRAYSIZE(g.TempBuffer), fmt, args);
8171  return TreeNodeBehavior(window->GetID(ptr_id), flags, g.TempBuffer, label_end);
8172 }
8173 
8174 bool ImGui::TreeNodeV(const char* str_id, const char* fmt, va_list args)
8175 {
8176  return TreeNodeExV(str_id, 0, fmt, args);
8177 }
8178 
8179 bool ImGui::TreeNodeV(const void* ptr_id, const char* fmt, va_list args)
8180 {
8181  return TreeNodeExV(ptr_id, 0, fmt, args);
8182 }
8183 
8184 bool ImGui::TreeNodeEx(const char* str_id, ImGuiTreeNodeFlags flags, const char* fmt, ...)
8185 {
8186  va_list args;
8187  va_start(args, fmt);
8188  bool is_open = TreeNodeExV(str_id, flags, fmt, args);
8189  va_end(args);
8190  return is_open;
8191 }
8192 
8193 bool ImGui::TreeNodeEx(const void* ptr_id, ImGuiTreeNodeFlags flags, const char* fmt, ...)
8194 {
8195  va_list args;
8196  va_start(args, fmt);
8197  bool is_open = TreeNodeExV(ptr_id, flags, fmt, args);
8198  va_end(args);
8199  return is_open;
8200 }
8201 
8202 bool ImGui::TreeNode(const char* str_id, const char* fmt, ...)
8203 {
8204  va_list args;
8205  va_start(args, fmt);
8206  bool is_open = TreeNodeExV(str_id, 0, fmt, args);
8207  va_end(args);
8208  return is_open;
8209 }
8210 
8211 bool ImGui::TreeNode(const void* ptr_id, const char* fmt, ...)
8212 {
8213  va_list args;
8214  va_start(args, fmt);
8215  bool is_open = TreeNodeExV(ptr_id, 0, fmt, args);
8216  va_end(args);
8217  return is_open;
8218 }
8219 
8220 bool ImGui::TreeNode(const char* label)
8221 {
8222  ImGuiWindow* window = GetCurrentWindow();
8223  if (window->SkipItems)
8224  return false;
8225  return TreeNodeBehavior(window->GetID(label), 0, label, NULL);
8226 }
8227 
8229 {
8230  ImGuiContext& g = *GImGui;
8232 }
8233 
8234 // Horizontal distance preceding label when using TreeNode() or Bullet()
8236 {
8237  ImGuiContext& g = *GImGui;
8238  return g.FontSize + (g.Style.FramePadding.x * 2.0f);
8239 }
8240 
8241 void ImGui::SetNextTreeNodeOpen(bool is_open, ImGuiCond cond)
8242 {
8243  ImGuiContext& g = *GImGui;
8244  if (g.CurrentWindow->SkipItems)
8245  return;
8246  g.NextTreeNodeOpenVal = is_open;
8247  g.NextTreeNodeOpenCond = cond ? cond : ImGuiCond_Always;
8248 }
8249 
8250 void ImGui::PushID(const char* str_id)
8251 {
8252  ImGuiWindow* window = GetCurrentWindowRead();
8253  window->IDStack.push_back(window->GetID(str_id));
8254 }
8255 
8256 void ImGui::PushID(const char* str_id_begin, const char* str_id_end)
8257 {
8258  ImGuiWindow* window = GetCurrentWindowRead();
8259  window->IDStack.push_back(window->GetID(str_id_begin, str_id_end));
8260 }
8261 
8262 void ImGui::PushID(const void* ptr_id)
8263 {
8264  ImGuiWindow* window = GetCurrentWindowRead();
8265  window->IDStack.push_back(window->GetID(ptr_id));
8266 }
8267 
8268 void ImGui::PushID(int int_id)
8269 {
8270  const void* ptr_id = (void*)(intptr_t)int_id;
8271  ImGuiWindow* window = GetCurrentWindowRead();
8272  window->IDStack.push_back(window->GetID(ptr_id));
8273 }
8274 
8276 {
8277  ImGuiWindow* window = GetCurrentWindowRead();
8278  window->IDStack.pop_back();
8279 }
8280 
8281 ImGuiID ImGui::GetID(const char* str_id)
8282 {
8283  return GImGui->CurrentWindow->GetID(str_id);
8284 }
8285 
8286 ImGuiID ImGui::GetID(const char* str_id_begin, const char* str_id_end)
8287 {
8288  return GImGui->CurrentWindow->GetID(str_id_begin, str_id_end);
8289 }
8290 
8291 ImGuiID ImGui::GetID(const void* ptr_id)
8292 {
8293  return GImGui->CurrentWindow->GetID(ptr_id);
8294 }
8295 
8297 {
8298  ImGuiWindow* window = GetCurrentWindow();
8299  if (window->SkipItems)
8300  return;
8301 
8302  ImGuiContext& g = *GImGui;
8303  const ImGuiStyle& style = g.Style;
8304  const float line_height = ImMax(ImMin(window->DC.CurrentLineHeight, g.FontSize + g.Style.FramePadding.y*2), g.FontSize);
8305  const ImRect bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(g.FontSize, line_height));
8306  ItemSize(bb);
8307  if (!ItemAdd(bb, 0))
8308  {
8309  SameLine(0, style.FramePadding.x*2);
8310  return;
8311  }
8312 
8313  // Render and stay on same line
8314  RenderBullet(bb.Min + ImVec2(style.FramePadding.x + g.FontSize*0.5f, line_height*0.5f));
8315  SameLine(0, style.FramePadding.x*2);
8316 }
8317 
8318 // Text with a little bullet aligned to the typical tree node.
8319 void ImGui::BulletTextV(const char* fmt, va_list args)
8320 {
8321  ImGuiWindow* window = GetCurrentWindow();
8322  if (window->SkipItems)
8323  return;
8324 
8325  ImGuiContext& g = *GImGui;
8326  const ImGuiStyle& style = g.Style;
8327 
8328  const char* text_begin = g.TempBuffer;
8329  const char* text_end = text_begin + ImFormatStringV(g.TempBuffer, IM_ARRAYSIZE(g.TempBuffer), fmt, args);
8330  const ImVec2 label_size = CalcTextSize(text_begin, text_end, false);
8331  const float text_base_offset_y = ImMax(0.0f, window->DC.CurrentLineTextBaseOffset); // Latch before ItemSize changes it
8332  const float line_height = ImMax(ImMin(window->DC.CurrentLineHeight, g.FontSize + g.Style.FramePadding.y*2), g.FontSize);
8333  const ImRect bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(g.FontSize + (label_size.x > 0.0f ? (label_size.x + style.FramePadding.x*2) : 0.0f), ImMax(line_height, label_size.y))); // Empty text doesn't add padding
8334  ItemSize(bb);
8335  if (!ItemAdd(bb, 0))
8336  return;
8337 
8338  // Render
8339  RenderBullet(bb.Min + ImVec2(style.FramePadding.x + g.FontSize*0.5f, line_height*0.5f));
8340  RenderText(bb.Min+ImVec2(g.FontSize + style.FramePadding.x*2, text_base_offset_y), text_begin, text_end, false);
8341 }
8342 
8343 void ImGui::BulletText(const char* fmt, ...)
8344 {
8345  va_list args;
8346  va_start(args, fmt);
8347  BulletTextV(fmt, args);
8348  va_end(args);
8349 }
8350 
8351 static inline void DataTypeFormatString(ImGuiDataType data_type, void* data_ptr, const char* display_format, char* buf, int buf_size)
8352 {
8353  if (data_type == ImGuiDataType_Int)
8354  ImFormatString(buf, buf_size, display_format, *(int*)data_ptr);
8355  else if (data_type == ImGuiDataType_Float)
8356  ImFormatString(buf, buf_size, display_format, *(float*)data_ptr);
8357 }
8358 
8359 static inline void DataTypeFormatString(ImGuiDataType data_type, void* data_ptr, int decimal_precision, char* buf, int buf_size)
8360 {
8361  if (data_type == ImGuiDataType_Int)
8362  {
8363  if (decimal_precision < 0)
8364  ImFormatString(buf, buf_size, "%d", *(int*)data_ptr);
8365  else
8366  ImFormatString(buf, buf_size, "%.*d", decimal_precision, *(int*)data_ptr);
8367  }
8368  else if (data_type == ImGuiDataType_Float)
8369  {
8370  if (decimal_precision < 0)
8371  ImFormatString(buf, buf_size, "%f", *(float*)data_ptr); // Ideally we'd have a minimum decimal precision of 1 to visually denote that it is a float, while hiding non-significant digits?
8372  else
8373  ImFormatString(buf, buf_size, "%.*f", decimal_precision, *(float*)data_ptr);
8374  }
8375 }
8376 
8377 static void DataTypeApplyOp(ImGuiDataType data_type, int op, void* value1, const void* value2)// Store into value1
8378 {
8379  if (data_type == ImGuiDataType_Int)
8380  {
8381  if (op == '+')
8382  *(int*)value1 = *(int*)value1 + *(const int*)value2;
8383  else if (op == '-')
8384  *(int*)value1 = *(int*)value1 - *(const int*)value2;
8385  }
8386  else if (data_type == ImGuiDataType_Float)
8387  {
8388  if (op == '+')
8389  *(float*)value1 = *(float*)value1 + *(const float*)value2;
8390  else if (op == '-')
8391  *(float*)value1 = *(float*)value1 - *(const float*)value2;
8392  }
8393 }
8394 
8395 // User can input math operators (e.g. +100) to edit a numerical values.
8396 static bool DataTypeApplyOpFromText(const char* buf, const char* initial_value_buf, ImGuiDataType data_type, void* data_ptr, const char* scalar_format)
8397 {
8398  while (ImCharIsSpace(*buf))
8399  buf++;
8400 
8401  // We don't support '-' op because it would conflict with inputing negative value.
8402  // Instead you can use +-100 to subtract from an existing value
8403  char op = buf[0];
8404  if (op == '+' || op == '*' || op == '/')
8405  {
8406  buf++;
8407  while (ImCharIsSpace(*buf))
8408  buf++;
8409  }
8410  else
8411  {
8412  op = 0;
8413  }
8414  if (!buf[0])
8415  return false;
8416 
8417  if (data_type == ImGuiDataType_Int)
8418  {
8419  if (!scalar_format)
8420  scalar_format = "%d";
8421  int* v = (int*)data_ptr;
8422  const int old_v = *v;
8423  int arg0i = *v;
8424  if (op && sscanf(initial_value_buf, scalar_format, &arg0i) < 1)
8425  return false;
8426 
8427  // Store operand in a float so we can use fractional value for multipliers (*1.1), but constant always parsed as integer so we can fit big integers (e.g. 2000000003) past float precision
8428  float arg1f = 0.0f;
8429  if (op == '+') { if (sscanf(buf, "%f", &arg1f) == 1) *v = (int)(arg0i + arg1f); } // Add (use "+-" to subtract)
8430  else if (op == '*') { if (sscanf(buf, "%f", &arg1f) == 1) *v = (int)(arg0i * arg1f); } // Multiply
8431  else if (op == '/') { if (sscanf(buf, "%f", &arg1f) == 1 && arg1f != 0.0f) *v = (int)(arg0i / arg1f); }// Divide
8432  else { if (sscanf(buf, scalar_format, &arg0i) == 1) *v = arg0i; } // Assign constant (read as integer so big values are not lossy)
8433  return (old_v != *v);
8434  }
8435  else if (data_type == ImGuiDataType_Float)
8436  {
8437  // For floats we have to ignore format with precision (e.g. "%.2f") because sscanf doesn't take them in
8438  scalar_format = "%f";
8439  float* v = (float*)data_ptr;
8440  const float old_v = *v;
8441  float arg0f = *v;
8442  if (op && sscanf(initial_value_buf, scalar_format, &arg0f) < 1)
8443  return false;
8444 
8445  float arg1f = 0.0f;
8446  if (sscanf(buf, scalar_format, &arg1f) < 1)
8447  return false;
8448  if (op == '+') { *v = arg0f + arg1f; } // Add (use "+-" to subtract)
8449  else if (op == '*') { *v = arg0f * arg1f; } // Multiply
8450  else if (op == '/') { if (arg1f != 0.0f) *v = arg0f / arg1f; } // Divide
8451  else { *v = arg1f; } // Assign constant
8452  return (old_v != *v);
8453  }
8454 
8455  return false;
8456 }
8457 
8458 // Create text input in place of a slider (when CTRL+Clicking on slider)
8459 // FIXME: Logic is messy and confusing.
8460 bool ImGui::InputScalarAsWidgetReplacement(const ImRect& aabb, const char* label, ImGuiDataType data_type, void* data_ptr, ImGuiID id, int decimal_precision)
8461 {
8462  ImGuiContext& g = *GImGui;
8463  ImGuiWindow* window = GetCurrentWindow();
8464 
8465  // Our replacement widget will override the focus ID (registered previously to allow for a TAB focus to happen)
8466  // On the first frame, g.ScalarAsInputTextId == 0, then on subsequent frames it becomes == id
8467  SetActiveID(g.ScalarAsInputTextId, window);
8468  g.ActiveIdAllowNavDirFlags = (1 << ImGuiDir_Up) | (1 << ImGuiDir_Down);
8469  SetHoveredID(0);
8470  FocusableItemUnregister(window);
8471 
8472  char buf[32];
8473  DataTypeFormatString(data_type, data_ptr, decimal_precision, buf, IM_ARRAYSIZE(buf));
8475  if (g.ScalarAsInputTextId == 0) // First frame we started displaying the InputText widget
8476  {
8477  IM_ASSERT(g.ActiveId == id); // InputText ID expected to match the Slider ID (else we'd need to store them both, which is also possible)
8478  g.ScalarAsInputTextId = g.ActiveId;
8479  SetHoveredID(id);
8480  }
8481  if (text_value_changed)
8482  return DataTypeApplyOpFromText(buf, GImGui->InputTextState.InitialText.begin(), data_type, data_ptr, NULL);
8483  return false;
8484 }
8485 
8486 // Parse display precision back from the display format string
8487 int ImGui::ParseFormatPrecision(const char* fmt, int default_precision)
8488 {
8489  int precision = default_precision;
8490  while ((fmt = strchr(fmt, '%')) != NULL)
8491  {
8492  fmt++;
8493  if (fmt[0] == '%') { fmt++; continue; } // Ignore "%%"
8494  while (*fmt >= '0' && *fmt <= '9')
8495  fmt++;
8496  if (*fmt == '.')
8497  {
8498  fmt = ImAtoi(fmt + 1, &precision);
8500  precision = default_precision;
8501  }
8502  if (*fmt == 'e' || *fmt == 'E') // Maximum precision with scientific notation
8503  precision = -1;
8504  break;
8505  }
8506  return precision;
8507 }
8508 
8509 static float GetMinimumStepAtDecimalPrecision(int decimal_precision)
8510 {
8511  static const float min_steps[10] = { 1.0f, 0.1f, 0.01f, 0.001f, 0.0001f, 0.00001f, 0.000001f, 0.0000001f, 0.00000001f, 0.000000001f };
8512  return (decimal_precision >= 0 && decimal_precision < 10) ? min_steps[decimal_precision] : powf(10.0f, (float)-decimal_precision);
8513 }
8514 
8515 float ImGui::RoundScalar(float value, int decimal_precision)
8516 {
8517  // Round past decimal precision
8518  // So when our value is 1.99999 with a precision of 0.001 we'll end up rounding to 2.0
8519  // FIXME: Investigate better rounding methods
8520  if (decimal_precision < 0)
8521  return value;
8522  const float min_step = GetMinimumStepAtDecimalPrecision(decimal_precision);
8523  bool negative = value < 0.0f;
8524  value = fabsf(value);
8525  float remainder = fmodf(value, min_step);
8526  if (remainder <= min_step*0.5f)
8527  value -= remainder;
8528  else
8529  value += (min_step - remainder);
8530  return negative ? -value : value;
8531 }
8532 
8533 static inline float SliderBehaviorCalcRatioFromValue(float v, float v_min, float v_max, float power, float linear_zero_pos)
8534 {
8535  if (v_min == v_max)
8536  return 0.0f;
8537 
8538  const bool is_non_linear = (power < 1.0f-0.00001f) || (power > 1.0f+0.00001f);
8539  const float v_clamped = (v_min < v_max) ? ImClamp(v, v_min, v_max) : ImClamp(v, v_max, v_min);
8540  if (is_non_linear)
8541  {
8542  if (v_clamped < 0.0f)
8543  {
8544  const float f = 1.0f - (v_clamped - v_min) / (ImMin(0.0f,v_max) - v_min);
8545  return (1.0f - powf(f, 1.0f/power)) * linear_zero_pos;
8546  }
8547  else
8548  {
8549  const float f = (v_clamped - ImMax(0.0f,v_min)) / (v_max - ImMax(0.0f,v_min));
8550  return linear_zero_pos + powf(f, 1.0f/power) * (1.0f - linear_zero_pos);
8551  }
8552  }
8553 
8554  // Linear slider
8555  return (v_clamped - v_min) / (v_max - v_min);
8556 }
8557 
8558 bool ImGui::SliderBehavior(const ImRect& frame_bb, ImGuiID id, float* v, float v_min, float v_max, float power, int decimal_precision, ImGuiSliderFlags flags)
8559 {
8560  ImGuiContext& g = *GImGui;
8561  ImGuiWindow* window = GetCurrentWindow();
8562  const ImGuiStyle& style = g.Style;
8563 
8564  // Draw frame
8565  const ImU32 frame_col = GetColorU32((g.ActiveId == id && g.ActiveIdSource == ImGuiInputSource_Nav) ? ImGuiCol_FrameBgActive : ImGuiCol_FrameBg);
8566  RenderNavHighlight(frame_bb, id);
8567  RenderFrame(frame_bb.Min, frame_bb.Max, frame_col, true, style.FrameRounding);
8568 
8569  const bool is_non_linear = (power < 1.0f-0.00001f) || (power > 1.0f+0.00001f);
8570  const bool is_horizontal = (flags & ImGuiSliderFlags_Vertical) == 0;
8571 
8572  const float grab_padding = 2.0f;
8573  const float slider_sz = is_horizontal ? (frame_bb.GetWidth() - grab_padding * 2.0f) : (frame_bb.GetHeight() - grab_padding * 2.0f);
8574  float grab_sz;
8575  if (decimal_precision != 0)
8576  grab_sz = ImMin(style.GrabMinSize, slider_sz);
8577  else
8578  grab_sz = ImMin(ImMax(1.0f * (slider_sz / ((v_min < v_max ? v_max - v_min : v_min - v_max) + 1.0f)), style.GrabMinSize), slider_sz); // Integer sliders, if possible have the grab size represent 1 unit
8579  const float slider_usable_sz = slider_sz - grab_sz;
8580  const float slider_usable_pos_min = (is_horizontal ? frame_bb.Min.x : frame_bb.Min.y) + grab_padding + grab_sz*0.5f;
8581  const float slider_usable_pos_max = (is_horizontal ? frame_bb.Max.x : frame_bb.Max.y) - grab_padding - grab_sz*0.5f;
8582 
8583  // For logarithmic sliders that cross over sign boundary we want the exponential increase to be symmetric around 0.0f
8584  float linear_zero_pos = 0.0f; // 0.0->1.0f
8585  if (v_min * v_max < 0.0f)
8586  {
8587  // Different sign
8588  const float linear_dist_min_to_0 = powf(fabsf(0.0f - v_min), 1.0f/power);
8589  const float linear_dist_max_to_0 = powf(fabsf(v_max - 0.0f), 1.0f/power);
8590  linear_zero_pos = linear_dist_min_to_0 / (linear_dist_min_to_0+linear_dist_max_to_0);
8591  }
8592  else
8593  {
8594  // Same sign
8595  linear_zero_pos = v_min < 0.0f ? 1.0f : 0.0f;
8596  }
8597 
8598  // Process interacting with the slider
8599  bool value_changed = false;
8600  if (g.ActiveId == id)
8601  {
8602  bool set_new_value = false;
8603  float clicked_t = 0.0f;
8604  if (g.ActiveIdSource == ImGuiInputSource_Mouse)
8605  {
8606  if (!g.IO.MouseDown[0])
8607  {
8608  ClearActiveID();
8609  }
8610  else
8611  {
8612  const float mouse_abs_pos = is_horizontal ? g.IO.MousePos.x : g.IO.MousePos.y;
8613  clicked_t = (slider_usable_sz > 0.0f) ? ImClamp((mouse_abs_pos - slider_usable_pos_min) / slider_usable_sz, 0.0f, 1.0f) : 0.0f;
8614  if (!is_horizontal)
8615  clicked_t = 1.0f - clicked_t;
8616  set_new_value = true;
8617  }
8618  }
8619  else if (g.ActiveIdSource == ImGuiInputSource_Nav)
8620  {
8622  float delta = is_horizontal ? delta2.x : -delta2.y;
8623  if (g.NavActivatePressedId == id && !g.ActiveIdIsJustActivated)
8624  {
8625  ClearActiveID();
8626  }
8627  else if (delta != 0.0f)
8628  {
8629  clicked_t = SliderBehaviorCalcRatioFromValue(*v, v_min, v_max, power, linear_zero_pos);
8630  if (decimal_precision == 0 && !is_non_linear)
8631  {
8632  if (fabsf(v_max - v_min) <= 100.0f || IsNavInputDown(ImGuiNavInput_TweakSlow))
8633  delta = ((delta < 0.0f) ? -1.0f : +1.0f) / (v_max - v_min); // Gamepad/keyboard tweak speeds in integer steps
8634  else
8635  delta /= 100.0f;
8636  }
8637  else
8638  {
8639  delta /= 100.0f; // Gamepad/keyboard tweak speeds in % of slider bounds
8641  delta /= 10.0f;
8642  }
8644  delta *= 10.0f;
8645  set_new_value = true;
8646  if ((clicked_t >= 1.0f && delta > 0.0f) || (clicked_t <= 0.0f && delta < 0.0f)) // This is to avoid applying the saturation when already past the limits
8647  set_new_value = false;
8648  else
8649  clicked_t = ImSaturate(clicked_t + delta);
8650  }
8651  }
8652 
8653  if (set_new_value)
8654  {
8655  float new_value;
8656  if (is_non_linear)
8657  {
8658  // Account for logarithmic scale on both sides of the zero
8659  if (clicked_t < linear_zero_pos)
8660  {
8661  // Negative: rescale to the negative range before powering
8662  float a = 1.0f - (clicked_t / linear_zero_pos);
8663  a = powf(a, power);
8664  new_value = ImLerp(ImMin(v_max,0.0f), v_min, a);
8665  }
8666  else
8667  {
8668  // Positive: rescale to the positive range before powering
8669  float a;
8670  if (fabsf(linear_zero_pos - 1.0f) > 1.e-6f)
8671  a = (clicked_t - linear_zero_pos) / (1.0f - linear_zero_pos);
8672  else
8673  a = clicked_t;
8674  a = powf(a, power);
8675  new_value = ImLerp(ImMax(v_min,0.0f), v_max, a);
8676  }
8677  }
8678  else
8679  {
8680  // Linear slider
8681  new_value = ImLerp(v_min, v_max, clicked_t);
8682  }
8683 
8684  // Round past decimal precision
8685  new_value = RoundScalar(new_value, decimal_precision);
8686  if (*v != new_value)
8687  {
8688  *v = new_value;
8689  value_changed = true;
8690  }
8691  }
8692  }
8693 
8694  // Draw
8695  float grab_t = SliderBehaviorCalcRatioFromValue(*v, v_min, v_max, power, linear_zero_pos);
8696  if (!is_horizontal)
8697  grab_t = 1.0f - grab_t;
8698  const float grab_pos = ImLerp(slider_usable_pos_min, slider_usable_pos_max, grab_t);
8699  ImRect grab_bb;
8700  if (is_horizontal)
8701  grab_bb = ImRect(ImVec2(grab_pos - grab_sz*0.5f, frame_bb.Min.y + grab_padding), ImVec2(grab_pos + grab_sz*0.5f, frame_bb.Max.y - grab_padding));
8702  else
8703  grab_bb = ImRect(ImVec2(frame_bb.Min.x + grab_padding, grab_pos - grab_sz*0.5f), ImVec2(frame_bb.Max.x - grab_padding, grab_pos + grab_sz*0.5f));
8704  window->DrawList->AddRectFilled(grab_bb.Min, grab_bb.Max, GetColorU32(g.ActiveId == id ? ImGuiCol_SliderGrabActive : ImGuiCol_SliderGrab), style.GrabRounding);
8705 
8706  return value_changed;
8707 }
8708 
8709 // Use power!=1.0 for logarithmic sliders.
8710 // Adjust display_format to decorate the value with a prefix or a suffix.
8711 // "%.3f" 1.234
8712 // "%5.2f secs" 01.23 secs
8713 // "Gold: %.0f" Gold: 1
8714 bool ImGui::SliderFloat(const char* label, float* v, float v_min, float v_max, const char* display_format, float power)
8715 {
8716  ImGuiWindow* window = GetCurrentWindow();
8717  if (window->SkipItems)
8718  return false;
8719 
8720  ImGuiContext& g = *GImGui;
8721  const ImGuiStyle& style = g.Style;
8722  const ImGuiID id = window->GetID(label);
8723  const float w = CalcItemWidth();
8724 
8725  const ImVec2 label_size = CalcTextSize(label, NULL, true);
8726  const ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(w, label_size.y + style.FramePadding.y*2.0f));
8727  const ImRect total_bb(frame_bb.Min, frame_bb.Max + ImVec2(label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f, 0.0f));
8728 
8729  // NB- we don't call ItemSize() yet because we may turn into a text edit box below
8730  if (!ItemAdd(total_bb, id, &frame_bb))
8731  {
8732  ItemSize(total_bb, style.FramePadding.y);
8733  return false;
8734  }
8735  const bool hovered = ItemHoverable(frame_bb, id);
8736 
8737  if (!display_format)
8738  display_format = "%.3f";
8739  int decimal_precision = ParseFormatPrecision(display_format, 3);
8740 
8741  // Tabbing or CTRL-clicking on Slider turns it into an input box
8742  bool start_text_input = false;
8743  const bool tab_focus_requested = FocusableItemRegister(window, id);
8744  if (tab_focus_requested || (hovered && g.IO.MouseClicked[0]) || g.NavActivateId == id || (g.NavInputId == id && g.ScalarAsInputTextId != id))
8745  {
8746  SetActiveID(id, window);
8747  SetFocusID(id, window);
8748  FocusWindow(window);
8749  g.ActiveIdAllowNavDirFlags = (1 << ImGuiDir_Up) | (1 << ImGuiDir_Down);
8750  if (tab_focus_requested || g.IO.KeyCtrl || g.NavInputId == id)
8751  {
8752  start_text_input = true;
8753  g.ScalarAsInputTextId = 0;
8754  }
8755  }
8756  if (start_text_input || (g.ActiveId == id && g.ScalarAsInputTextId == id))
8757  return InputScalarAsWidgetReplacement(frame_bb, label, ImGuiDataType_Float, v, id, decimal_precision);
8758 
8759  // Actual slider behavior + render grab
8760  ItemSize(total_bb, style.FramePadding.y);
8761  const bool value_changed = SliderBehavior(frame_bb, id, v, v_min, v_max, power, decimal_precision);
8762 
8763  // Display value using user-provided display format so user can add prefix/suffix/decorations to the value.
8764  char value_buf[64];
8765  const char* value_buf_end = value_buf + ImFormatString(value_buf, IM_ARRAYSIZE(value_buf), display_format, *v);
8766  RenderTextClipped(frame_bb.Min, frame_bb.Max, value_buf, value_buf_end, NULL, ImVec2(0.5f,0.5f));
8767 
8768  if (label_size.x > 0.0f)
8769  RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, frame_bb.Min.y + style.FramePadding.y), label);
8770 
8771  return value_changed;
8772 }
8773 
8774 bool ImGui::VSliderFloat(const char* label, const ImVec2& size, float* v, float v_min, float v_max, const char* display_format, float power)
8775 {
8776  ImGuiWindow* window = GetCurrentWindow();
8777  if (window->SkipItems)
8778  return false;
8779 
8780  ImGuiContext& g = *GImGui;
8781  const ImGuiStyle& style = g.Style;
8782  const ImGuiID id = window->GetID(label);
8783 
8784  const ImVec2 label_size = CalcTextSize(label, NULL, true);
8785  const ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + size);
8786  const ImRect bb(frame_bb.Min, frame_bb.Max + ImVec2(label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f, 0.0f));
8787 
8788  ItemSize(bb, style.FramePadding.y);
8789  if (!ItemAdd(frame_bb, id))
8790  return false;
8791  const bool hovered = ItemHoverable(frame_bb, id);
8792 
8793  if (!display_format)
8794  display_format = "%.3f";
8795  int decimal_precision = ParseFormatPrecision(display_format, 3);
8796 
8797  if ((hovered && g.IO.MouseClicked[0]) || g.NavActivateId == id || g.NavInputId == id)
8798  {
8799  SetActiveID(id, window);
8800  SetFocusID(id, window);
8801  FocusWindow(window);
8802  g.ActiveIdAllowNavDirFlags = (1 << ImGuiDir_Left) | (1 << ImGuiDir_Right);
8803  }
8804 
8805  // Actual slider behavior + render grab
8806  bool value_changed = SliderBehavior(frame_bb, id, v, v_min, v_max, power, decimal_precision, ImGuiSliderFlags_Vertical);
8807 
8808  // Display value using user-provided display format so user can add prefix/suffix/decorations to the value.
8809  // For the vertical slider we allow centered text to overlap the frame padding
8810  char value_buf[64];
8811  char* value_buf_end = value_buf + ImFormatString(value_buf, IM_ARRAYSIZE(value_buf), display_format, *v);
8812  RenderTextClipped(ImVec2(frame_bb.Min.x, frame_bb.Min.y + style.FramePadding.y), frame_bb.Max, value_buf, value_buf_end, NULL, ImVec2(0.5f,0.0f));
8813  if (label_size.x > 0.0f)
8814  RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, frame_bb.Min.y + style.FramePadding.y), label);
8815 
8816  return value_changed;
8817 }
8818 
8819 bool ImGui::SliderAngle(const char* label, float* v_rad, float v_degrees_min, float v_degrees_max)
8820 {
8821  float v_deg = (*v_rad) * 360.0f / (2*IM_PI);
8822  bool value_changed = SliderFloat(label, &v_deg, v_degrees_min, v_degrees_max, "%.0f deg", 1.0f);
8823  *v_rad = v_deg * (2*IM_PI) / 360.0f;
8824  return value_changed;
8825 }
8826 
8827 bool ImGui::SliderInt(const char* label, int* v, int v_min, int v_max, const char* display_format)
8828 {
8829  if (!display_format)
8830  display_format = "%.0f";
8831  float v_f = (float)*v;
8832  bool value_changed = SliderFloat(label, &v_f, (float)v_min, (float)v_max, display_format, 1.0f);
8833  *v = (int)v_f;
8834  return value_changed;
8835 }
8836 
8837 bool ImGui::VSliderInt(const char* label, const ImVec2& size, int* v, int v_min, int v_max, const char* display_format)
8838 {
8839  if (!display_format)
8840  display_format = "%.0f";
8841  float v_f = (float)*v;
8842  bool value_changed = VSliderFloat(label, size, &v_f, (float)v_min, (float)v_max, display_format, 1.0f);
8843  *v = (int)v_f;
8844  return value_changed;
8845 }
8846 
8847 // Add multiple sliders on 1 line for compact edition of multiple components
8848 bool ImGui::SliderFloatN(const char* label, float* v, int components, float v_min, float v_max, const char* display_format, float power)
8849 {
8850  ImGuiWindow* window = GetCurrentWindow();
8851  if (window->SkipItems)
8852  return false;
8853 
8854  ImGuiContext& g = *GImGui;
8855  bool value_changed = false;
8856  BeginGroup();
8857  PushID(label);
8859  for (int i = 0; i < components; i++)
8860  {
8861  PushID(i);
8862  value_changed |= SliderFloat("##v", &v[i], v_min, v_max, display_format, power);
8863  SameLine(0, g.Style.ItemInnerSpacing.x);
8864  PopID();
8865  PopItemWidth();
8866  }
8867  PopID();
8868 
8870  EndGroup();
8871 
8872  return value_changed;
8873 }
8874 
8875 bool ImGui::SliderFloat2(const char* label, float v[2], float v_min, float v_max, const char* display_format, float power)
8876 {
8877  return SliderFloatN(label, v, 2, v_min, v_max, display_format, power);
8878 }
8879 
8880 bool ImGui::SliderFloat3(const char* label, float v[3], float v_min, float v_max, const char* display_format, float power)
8881 {
8882  return SliderFloatN(label, v, 3, v_min, v_max, display_format, power);
8883 }
8884 
8885 bool ImGui::SliderFloat4(const char* label, float v[4], float v_min, float v_max, const char* display_format, float power)
8886 {
8887  return SliderFloatN(label, v, 4, v_min, v_max, display_format, power);
8888 }
8889 
8890 bool ImGui::SliderIntN(const char* label, int* v, int components, int v_min, int v_max, const char* display_format)
8891 {
8892  ImGuiWindow* window = GetCurrentWindow();
8893  if (window->SkipItems)
8894  return false;
8895 
8896  ImGuiContext& g = *GImGui;
8897  bool value_changed = false;
8898  BeginGroup();
8899  PushID(label);
8901  for (int i = 0; i < components; i++)
8902  {
8903  PushID(i);
8904  value_changed |= SliderInt("##v", &v[i], v_min, v_max, display_format);
8905  SameLine(0, g.Style.ItemInnerSpacing.x);
8906  PopID();
8907  PopItemWidth();
8908  }
8909  PopID();
8910 
8912  EndGroup();
8913 
8914  return value_changed;
8915 }
8916 
8917 bool ImGui::SliderInt2(const char* label, int v[2], int v_min, int v_max, const char* display_format)
8918 {
8919  return SliderIntN(label, v, 2, v_min, v_max, display_format);
8920 }
8921 
8922 bool ImGui::SliderInt3(const char* label, int v[3], int v_min, int v_max, const char* display_format)
8923 {
8924  return SliderIntN(label, v, 3, v_min, v_max, display_format);
8925 }
8926 
8927 bool ImGui::SliderInt4(const char* label, int v[4], int v_min, int v_max, const char* display_format)
8928 {
8929  return SliderIntN(label, v, 4, v_min, v_max, display_format);
8930 }
8931 
8932 bool ImGui::DragBehavior(const ImRect& frame_bb, ImGuiID id, float* v, float v_speed, float v_min, float v_max, int decimal_precision, float power)
8933 {
8934  ImGuiContext& g = *GImGui;
8935  const ImGuiStyle& style = g.Style;
8936 
8937  // Draw frame
8938  const ImU32 frame_col = GetColorU32(g.ActiveId == id ? ImGuiCol_FrameBgActive : g.HoveredId == id ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg);
8939  RenderNavHighlight(frame_bb, id);
8940  RenderFrame(frame_bb.Min, frame_bb.Max, frame_col, true, style.FrameRounding);
8941 
8942  bool value_changed = false;
8943 
8944  // Process interacting with the drag
8945  if (g.ActiveId == id)
8946  {
8947  if (g.ActiveIdSource == ImGuiInputSource_Mouse && !g.IO.MouseDown[0])
8948  ClearActiveID();
8949  else if (g.ActiveIdSource == ImGuiInputSource_Nav && g.NavActivatePressedId == id && !g.ActiveIdIsJustActivated)
8950  ClearActiveID();
8951  }
8952  if (g.ActiveId == id)
8953  {
8954  if (g.ActiveIdIsJustActivated)
8955  {
8956  // Lock current value on click
8957  g.DragCurrentValue = *v;
8958  g.DragLastMouseDelta = ImVec2(0.f, 0.f);
8959  }
8960 
8961  if (v_speed == 0.0f && (v_max - v_min) != 0.0f && (v_max - v_min) < FLT_MAX)
8962  v_speed = (v_max - v_min) * g.DragSpeedDefaultRatio;
8963 
8964  float v_cur = g.DragCurrentValue;
8965  const ImVec2 mouse_drag_delta = GetMouseDragDelta(0, 1.0f);
8966  float adjust_delta = 0.0f;
8967  if (g.ActiveIdSource == ImGuiInputSource_Mouse && IsMousePosValid())
8968  {
8969  adjust_delta = mouse_drag_delta.x - g.DragLastMouseDelta.x;
8970  if (g.IO.KeyShift && g.DragSpeedScaleFast >= 0.0f)
8971  adjust_delta *= g.DragSpeedScaleFast;
8972  if (g.IO.KeyAlt && g.DragSpeedScaleSlow >= 0.0f)
8973  adjust_delta *= g.DragSpeedScaleSlow;
8974  g.DragLastMouseDelta.x = mouse_drag_delta.x;
8975  }
8976  if (g.ActiveIdSource == ImGuiInputSource_Nav)
8977  {
8979  if (v_min < v_max && ((v_cur >= v_max && adjust_delta > 0.0f) || (v_cur <= v_min && adjust_delta < 0.0f))) // This is to avoid applying the saturation when already past the limits
8980  adjust_delta = 0.0f;
8981  v_speed = ImMax(v_speed, GetMinimumStepAtDecimalPrecision(decimal_precision));
8982  }
8983  adjust_delta *= v_speed;
8984 
8985  if (fabsf(adjust_delta) > 0.0f)
8986  {
8987  if (fabsf(power - 1.0f) > 0.001f)
8988  {
8989  // Logarithmic curve on both side of 0.0
8990  float v0_abs = v_cur >= 0.0f ? v_cur : -v_cur;
8991  float v0_sign = v_cur >= 0.0f ? 1.0f : -1.0f;
8992  float v1 = powf(v0_abs, 1.0f / power) + (adjust_delta * v0_sign);
8993  float v1_abs = v1 >= 0.0f ? v1 : -v1;
8994  float v1_sign = v1 >= 0.0f ? 1.0f : -1.0f; // Crossed sign line
8995  v_cur = powf(v1_abs, power) * v0_sign * v1_sign; // Reapply sign
8996  }
8997  else
8998  {
8999  v_cur += adjust_delta;
9000  }
9001 
9002  // Clamp
9003  if (v_min < v_max)
9004  v_cur = ImClamp(v_cur, v_min, v_max);
9005  g.DragCurrentValue = v_cur;
9006  }
9007 
9008  // Round to user desired precision, then apply
9009  v_cur = RoundScalar(v_cur, decimal_precision);
9010  if (*v != v_cur)
9011  {
9012  *v = v_cur;
9013  value_changed = true;
9014  }
9015  }
9016 
9017  return value_changed;
9018 }
9019 
9020 bool ImGui::DragFloat(const char* label, float* v, float v_speed, float v_min, float v_max, const char* display_format, float power)
9021 {
9022  ImGuiWindow* window = GetCurrentWindow();
9023  if (window->SkipItems)
9024  return false;
9025 
9026  ImGuiContext& g = *GImGui;
9027  const ImGuiStyle& style = g.Style;
9028  const ImGuiID id = window->GetID(label);
9029  const float w = CalcItemWidth();
9030 
9031  const ImVec2 label_size = CalcTextSize(label, NULL, true);
9032  const ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(w, label_size.y + style.FramePadding.y*2.0f));
9033  const ImRect inner_bb(frame_bb.Min + style.FramePadding, frame_bb.Max - style.FramePadding);
9034  const ImRect total_bb(frame_bb.Min, frame_bb.Max + ImVec2(label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f, 0.0f));
9035 
9036  // NB- we don't call ItemSize() yet because we may turn into a text edit box below
9037  if (!ItemAdd(total_bb, id, &frame_bb))
9038  {
9039  ItemSize(total_bb, style.FramePadding.y);
9040  return false;
9041  }
9042  const bool hovered = ItemHoverable(frame_bb, id);
9043 
9044  if (!display_format)
9045  display_format = "%.3f";
9046  int decimal_precision = ParseFormatPrecision(display_format, 3);
9047 
9048  // Tabbing or CTRL-clicking on Drag turns it into an input box
9049  bool start_text_input = false;
9050  const bool tab_focus_requested = FocusableItemRegister(window, id);
9051  if (tab_focus_requested || (hovered && (g.IO.MouseClicked[0] || g.IO.MouseDoubleClicked[0])) || g.NavActivateId == id || (g.NavInputId == id && g.ScalarAsInputTextId != id))
9052  {
9053  SetActiveID(id, window);
9054  SetFocusID(id, window);
9055  FocusWindow(window);
9056  g.ActiveIdAllowNavDirFlags = (1 << ImGuiDir_Up) | (1 << ImGuiDir_Down);
9057  if (tab_focus_requested || g.IO.KeyCtrl || g.IO.MouseDoubleClicked[0] || g.NavInputId == id)
9058  {
9059  start_text_input = true;
9060  g.ScalarAsInputTextId = 0;
9061  }
9062  }
9063  if (start_text_input || (g.ActiveId == id && g.ScalarAsInputTextId == id))
9064  return InputScalarAsWidgetReplacement(frame_bb, label, ImGuiDataType_Float, v, id, decimal_precision);
9065 
9066  // Actual drag behavior
9067  ItemSize(total_bb, style.FramePadding.y);
9068  const bool value_changed = DragBehavior(frame_bb, id, v, v_speed, v_min, v_max, decimal_precision, power);
9069 
9070  // Display value using user-provided display format so user can add prefix/suffix/decorations to the value.
9071  char value_buf[64];
9072  const char* value_buf_end = value_buf + ImFormatString(value_buf, IM_ARRAYSIZE(value_buf), display_format, *v);
9073  RenderTextClipped(frame_bb.Min, frame_bb.Max, value_buf, value_buf_end, NULL, ImVec2(0.5f,0.5f));
9074 
9075  if (label_size.x > 0.0f)
9076  RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, inner_bb.Min.y), label);
9077 
9078  return value_changed;
9079 }
9080 
9081 bool ImGui::DragFloatN(const char* label, float* v, int components, float v_speed, float v_min, float v_max, const char* display_format, float power)
9082 {
9083  ImGuiWindow* window = GetCurrentWindow();
9084  if (window->SkipItems)
9085  return false;
9086 
9087  ImGuiContext& g = *GImGui;
9088  bool value_changed = false;
9089  BeginGroup();
9090  PushID(label);
9092  for (int i = 0; i < components; i++)
9093  {
9094  PushID(i);
9095  value_changed |= DragFloat("##v", &v[i], v_speed, v_min, v_max, display_format, power);
9096  SameLine(0, g.Style.ItemInnerSpacing.x);
9097  PopID();
9098  PopItemWidth();
9099  }
9100  PopID();
9101 
9103  EndGroup();
9104 
9105  return value_changed;
9106 }
9107 
9108 bool ImGui::DragFloat2(const char* label, float v[2], float v_speed, float v_min, float v_max, const char* display_format, float power)
9109 {
9110  return DragFloatN(label, v, 2, v_speed, v_min, v_max, display_format, power);
9111 }
9112 
9113 bool ImGui::DragFloat3(const char* label, float v[3], float v_speed, float v_min, float v_max, const char* display_format, float power)
9114 {
9115  return DragFloatN(label, v, 3, v_speed, v_min, v_max, display_format, power);
9116 }
9117 
9118 bool ImGui::DragFloat4(const char* label, float v[4], float v_speed, float v_min, float v_max, const char* display_format, float power)
9119 {
9120  return DragFloatN(label, v, 4, v_speed, v_min, v_max, display_format, power);
9121 }
9122 
9123 bool ImGui::DragFloatRange2(const char* label, float* v_current_min, float* v_current_max, float v_speed, float v_min, float v_max, const char* display_format, const char* display_format_max, float power)
9124 {
9125  ImGuiWindow* window = GetCurrentWindow();
9126  if (window->SkipItems)
9127  return false;
9128 
9129  ImGuiContext& g = *GImGui;
9130  PushID(label);
9131  BeginGroup();
9133 
9134  bool value_changed = DragFloat("##min", v_current_min, v_speed, (v_min >= v_max) ? -FLT_MAX : v_min, (v_min >= v_max) ? *v_current_max : ImMin(v_max, *v_current_max), display_format, power);
9135  PopItemWidth();
9136  SameLine(0, g.Style.ItemInnerSpacing.x);
9137  value_changed |= DragFloat("##max", v_current_max, v_speed, (v_min >= v_max) ? *v_current_min : ImMax(v_min, *v_current_min), (v_min >= v_max) ? FLT_MAX : v_max, display_format_max ? display_format_max : display_format, power);
9138  PopItemWidth();
9139  SameLine(0, g.Style.ItemInnerSpacing.x);
9140 
9142  EndGroup();
9143  PopID();
9144 
9145  return value_changed;
9146 }
9147 
9148 // NB: v_speed is float to allow adjusting the drag speed with more precision
9149 bool ImGui::DragInt(const char* label, int* v, float v_speed, int v_min, int v_max, const char* display_format)
9150 {
9151  if (!display_format)
9152  display_format = "%.0f";
9153  float v_f = (float)*v;
9154  bool value_changed = DragFloat(label, &v_f, v_speed, (float)v_min, (float)v_max, display_format);
9155  *v = (int)v_f;
9156  return value_changed;
9157 }
9158 
9159 bool ImGui::DragIntN(const char* label, int* v, int components, float v_speed, int v_min, int v_max, const char* display_format)
9160 {
9161  ImGuiWindow* window = GetCurrentWindow();
9162  if (window->SkipItems)
9163  return false;
9164 
9165  ImGuiContext& g = *GImGui;
9166  bool value_changed = false;
9167  BeginGroup();
9168  PushID(label);
9170  for (int i = 0; i < components; i++)
9171  {
9172  PushID(i);
9173  value_changed |= DragInt("##v", &v[i], v_speed, v_min, v_max, display_format);
9174  SameLine(0, g.Style.ItemInnerSpacing.x);
9175  PopID();
9176  PopItemWidth();
9177  }
9178  PopID();
9179 
9181  EndGroup();
9182 
9183  return value_changed;
9184 }
9185 
9186 bool ImGui::DragInt2(const char* label, int v[2], float v_speed, int v_min, int v_max, const char* display_format)
9187 {
9188  return DragIntN(label, v, 2, v_speed, v_min, v_max, display_format);
9189 }
9190 
9191 bool ImGui::DragInt3(const char* label, int v[3], float v_speed, int v_min, int v_max, const char* display_format)
9192 {
9193  return DragIntN(label, v, 3, v_speed, v_min, v_max, display_format);
9194 }
9195 
9196 bool ImGui::DragInt4(const char* label, int v[4], float v_speed, int v_min, int v_max, const char* display_format)
9197 {
9198  return DragIntN(label, v, 4, v_speed, v_min, v_max, display_format);
9199 }
9200 
9201 bool ImGui::DragIntRange2(const char* label, int* v_current_min, int* v_current_max, float v_speed, int v_min, int v_max, const char* display_format, const char* display_format_max)
9202 {
9203  ImGuiWindow* window = GetCurrentWindow();
9204  if (window->SkipItems)
9205  return false;
9206 
9207  ImGuiContext& g = *GImGui;
9208  PushID(label);
9209  BeginGroup();
9211 
9212  bool value_changed = DragInt("##min", v_current_min, v_speed, (v_min >= v_max) ? INT_MIN : v_min, (v_min >= v_max) ? *v_current_max : ImMin(v_max, *v_current_max), display_format);
9213  PopItemWidth();
9214  SameLine(0, g.Style.ItemInnerSpacing.x);
9215  value_changed |= DragInt("##max", v_current_max, v_speed, (v_min >= v_max) ? *v_current_min : ImMax(v_min, *v_current_min), (v_min >= v_max) ? INT_MAX : v_max, display_format_max ? display_format_max : display_format);
9216  PopItemWidth();
9217  SameLine(0, g.Style.ItemInnerSpacing.x);
9218 
9220  EndGroup();
9221  PopID();
9222 
9223  return value_changed;
9224 }
9225 
9226 void ImGui::PlotEx(ImGuiPlotType plot_type, const char* label, float (*values_getter)(void* data, int idx), void* data, int values_count, int values_offset, const char* overlay_text, float scale_min, float scale_max, ImVec2 graph_size)
9227 {
9228  ImGuiWindow* window = GetCurrentWindow();
9229  if (window->SkipItems)
9230  return;
9231 
9232  ImGuiContext& g = *GImGui;
9233  const ImGuiStyle& style = g.Style;
9234 
9235  const ImVec2 label_size = CalcTextSize(label, NULL, true);
9236  if (graph_size.x == 0.0f)
9237  graph_size.x = CalcItemWidth();
9238  if (graph_size.y == 0.0f)
9239  graph_size.y = label_size.y + (style.FramePadding.y * 2);
9240 
9241  const ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(graph_size.x, graph_size.y));
9242  const ImRect inner_bb(frame_bb.Min + style.FramePadding, frame_bb.Max - style.FramePadding);
9243  const ImRect total_bb(frame_bb.Min, frame_bb.Max + ImVec2(label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f, 0));
9244  ItemSize(total_bb, style.FramePadding.y);
9245  if (!ItemAdd(total_bb, 0, &frame_bb))
9246  return;
9247  const bool hovered = ItemHoverable(inner_bb, 0);
9248 
9249  // Determine scale from values if not specified
9250  if (scale_min == FLT_MAX || scale_max == FLT_MAX)
9251  {
9252  float v_min = FLT_MAX;
9253  float v_max = -FLT_MAX;
9254  for (int i = 0; i < values_count; i++)
9255  {
9256  const float v = values_getter(data, i);
9257  v_min = ImMin(v_min, v);
9258  v_max = ImMax(v_max, v);
9259  }
9260  if (scale_min == FLT_MAX)
9261  scale_min = v_min;
9262  if (scale_max == FLT_MAX)
9263  scale_max = v_max;
9264  }
9265 
9266  RenderFrame(frame_bb.Min, frame_bb.Max, GetColorU32(ImGuiCol_FrameBg), true, style.FrameRounding);
9267 
9268  if (values_count > 0)
9269  {
9270  int res_w = ImMin((int)graph_size.x, values_count) + ((plot_type == ImGuiPlotType_Lines) ? -1 : 0);
9271  int item_count = values_count + ((plot_type == ImGuiPlotType_Lines) ? -1 : 0);
9272 
9273  // Tooltip on hover
9274  int v_hovered = -1;
9275  if (hovered)
9276  {
9277  const float t = ImClamp((g.IO.MousePos.x - inner_bb.Min.x) / (inner_bb.Max.x - inner_bb.Min.x), 0.0f, 0.9999f);
9278  const int v_idx = (int)(t * item_count);
9279  IM_ASSERT(v_idx >= 0 && v_idx < values_count);
9280 
9281  const float v0 = values_getter(data, (v_idx + values_offset) % values_count);
9282  const float v1 = values_getter(data, (v_idx + 1 + values_offset) % values_count);
9283  if (plot_type == ImGuiPlotType_Lines)
9284  SetTooltip("%d: %8.4g\n%d: %8.4g", v_idx, v0, v_idx+1, v1);
9285  else if (plot_type == ImGuiPlotType_Histogram)
9286  SetTooltip("%d: %8.4g", v_idx, v0);
9287  v_hovered = v_idx;
9288  }
9289 
9290  const float t_step = 1.0f / (float)res_w;
9291  const float inv_scale = (scale_min == scale_max) ? 0.0f : (1.0f / (scale_max - scale_min));
9292 
9293  float v0 = values_getter(data, (0 + values_offset) % values_count);
9294  float t0 = 0.0f;
9295  ImVec2 tp0 = ImVec2( t0, 1.0f - ImSaturate((v0 - scale_min) * inv_scale) ); // Point in the normalized space of our target rectangle
9296  float histogram_zero_line_t = (scale_min * scale_max < 0.0f) ? (-scale_min * inv_scale) : (scale_min < 0.0f ? 0.0f : 1.0f); // Where does the zero line stands
9297 
9298  const ImU32 col_base = GetColorU32((plot_type == ImGuiPlotType_Lines) ? ImGuiCol_PlotLines : ImGuiCol_PlotHistogram);
9300 
9301  for (int n = 0; n < res_w; n++)
9302  {
9303  const float t1 = t0 + t_step;
9304  const int v1_idx = (int)(t0 * item_count + 0.5f);
9305  IM_ASSERT(v1_idx >= 0 && v1_idx < values_count);
9306  const float v1 = values_getter(data, (v1_idx + values_offset + 1) % values_count);
9307  const ImVec2 tp1 = ImVec2( t1, 1.0f - ImSaturate((v1 - scale_min) * inv_scale) );
9308 
9309  // NB: Draw calls are merged together by the DrawList system. Still, we should render our batch are lower level to save a bit of CPU.
9310  ImVec2 pos0 = ImLerp(inner_bb.Min, inner_bb.Max, tp0);
9311  ImVec2 pos1 = ImLerp(inner_bb.Min, inner_bb.Max, (plot_type == ImGuiPlotType_Lines) ? tp1 : ImVec2(tp1.x, histogram_zero_line_t));
9312  if (plot_type == ImGuiPlotType_Lines)
9313  {
9314  window->DrawList->AddLine(pos0, pos1, v_hovered == v1_idx ? col_hovered : col_base);
9315  }
9316  else if (plot_type == ImGuiPlotType_Histogram)
9317  {
9318  if (pos1.x >= pos0.x + 2.0f)
9319  pos1.x -= 1.0f;
9320  window->DrawList->AddRectFilled(pos0, pos1, v_hovered == v1_idx ? col_hovered : col_base);
9321  }
9322 
9323  t0 = t1;
9324  tp0 = tp1;
9325  }
9326  }
9327 
9328  // Text overlay
9329  if (overlay_text)
9330  RenderTextClipped(ImVec2(frame_bb.Min.x, frame_bb.Min.y + style.FramePadding.y), frame_bb.Max, overlay_text, NULL, NULL, ImVec2(0.5f,0.0f));
9331 
9332  if (label_size.x > 0.0f)
9333  RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, inner_bb.Min.y), label);
9334 }
9335 
9337 {
9338  const float* Values;
9339  int Stride;
9340 
9341  ImGuiPlotArrayGetterData(const float* values, int stride) { Values = values; Stride = stride; }
9342 };
9343 
9344 static float Plot_ArrayGetter(void* data, int idx)
9345 {
9347  const float v = *(float*)(void*)((unsigned char*)plot_data->Values + (size_t)idx * plot_data->Stride);
9348  return v;
9349 }
9350 
9351 void ImGui::PlotLines(const char* label, const float* values, int values_count, int values_offset, const char* overlay_text, float scale_min, float scale_max, ImVec2 graph_size, int stride)
9352 {
9354  PlotEx(ImGuiPlotType_Lines, label, &Plot_ArrayGetter, (void*)&data, values_count, values_offset, overlay_text, scale_min, scale_max, graph_size);
9355 }
9356 
9357 void ImGui::PlotLines(const char* label, float (*values_getter)(void* data, int idx), void* data, int values_count, int values_offset, const char* overlay_text, float scale_min, float scale_max, ImVec2 graph_size)
9358 {
9359  PlotEx(ImGuiPlotType_Lines, label, values_getter, data, values_count, values_offset, overlay_text, scale_min, scale_max, graph_size);
9360 }
9361 
9362 void ImGui::PlotHistogram(const char* label, const float* values, int values_count, int values_offset, const char* overlay_text, float scale_min, float scale_max, ImVec2 graph_size, int stride)
9363 {
9365  PlotEx(ImGuiPlotType_Histogram, label, &Plot_ArrayGetter, (void*)&data, values_count, values_offset, overlay_text, scale_min, scale_max, graph_size);
9366 }
9367 
9368 void ImGui::PlotHistogram(const char* label, float (*values_getter)(void* data, int idx), void* data, int values_count, int values_offset, const char* overlay_text, float scale_min, float scale_max, ImVec2 graph_size)
9369 {
9370  PlotEx(ImGuiPlotType_Histogram, label, values_getter, data, values_count, values_offset, overlay_text, scale_min, scale_max, graph_size);
9371 }
9372 
9373 // size_arg (for each axis) < 0.0f: align to end, 0.0f: auto, > 0.0f: specified size
9374 void ImGui::ProgressBar(float fraction, const ImVec2& size_arg, const char* overlay)
9375 {
9376  ImGuiWindow* window = GetCurrentWindow();
9377  if (window->SkipItems)
9378  return;
9379 
9380  ImGuiContext& g = *GImGui;
9381  const ImGuiStyle& style = g.Style;
9382 
9383  ImVec2 pos = window->DC.CursorPos;
9384  ImRect bb(pos, pos + CalcItemSize(size_arg, CalcItemWidth(), g.FontSize + style.FramePadding.y*2.0f));
9385  ItemSize(bb, style.FramePadding.y);
9386  if (!ItemAdd(bb, 0))
9387  return;
9388 
9389  // Render
9390  fraction = ImSaturate(fraction);
9392  bb.Expand(ImVec2(-style.FrameBorderSize, -style.FrameBorderSize));
9393  const ImVec2 fill_br = ImVec2(ImLerp(bb.Min.x, bb.Max.x, fraction), bb.Max.y);
9395 
9396  // Default displaying the fraction as percentage string, but user can override it
9397  char overlay_buf[32];
9398  if (!overlay)
9399  {
9400  ImFormatString(overlay_buf, IM_ARRAYSIZE(overlay_buf), "%.0f%%", fraction*100+0.01f);
9401  overlay = overlay_buf;
9402  }
9403 
9404  ImVec2 overlay_size = CalcTextSize(overlay, NULL);
9405  if (overlay_size.x > 0.0f)
9406  RenderTextClipped(ImVec2(ImClamp(fill_br.x + style.ItemSpacing.x, bb.Min.x, bb.Max.x - overlay_size.x - style.ItemInnerSpacing.x), bb.Min.y), bb.Max, overlay, NULL, &overlay_size, ImVec2(0.0f,0.5f), &bb);
9407 }
9408 
9409 bool ImGui::Checkbox(const char* label, bool* v)
9410 {
9411  ImGuiWindow* window = GetCurrentWindow();
9412  if (window->SkipItems)
9413  return false;
9414 
9415  ImGuiContext& g = *GImGui;
9416  const ImGuiStyle& style = g.Style;
9417  const ImGuiID id = window->GetID(label);
9418  const ImVec2 label_size = CalcTextSize(label, NULL, true);
9419 
9420  const ImRect check_bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(label_size.y + style.FramePadding.y*2, label_size.y + style.FramePadding.y*2)); // We want a square shape to we use Y twice
9421  ItemSize(check_bb, style.FramePadding.y);
9422 
9423  ImRect total_bb = check_bb;
9424  if (label_size.x > 0)
9425  SameLine(0, style.ItemInnerSpacing.x);
9426  const ImRect text_bb(window->DC.CursorPos + ImVec2(0,style.FramePadding.y), window->DC.CursorPos + ImVec2(0,style.FramePadding.y) + label_size);
9427  if (label_size.x > 0)
9428  {
9429  ItemSize(ImVec2(text_bb.GetWidth(), check_bb.GetHeight()), style.FramePadding.y);
9430  total_bb = ImRect(ImMin(check_bb.Min, text_bb.Min), ImMax(check_bb.Max, text_bb.Max));
9431  }
9432 
9433  if (!ItemAdd(total_bb, id))
9434  return false;
9435 
9436  bool hovered, held;
9437  bool pressed = ButtonBehavior(total_bb, id, &hovered, &held);
9438  if (pressed)
9439  *v = !(*v);
9440 
9441  RenderNavHighlight(total_bb, id);
9442  RenderFrame(check_bb.Min, check_bb.Max, GetColorU32((held && hovered) ? ImGuiCol_FrameBgActive : hovered ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg), true, style.FrameRounding);
9443  if (*v)
9444  {
9445  const float check_sz = ImMin(check_bb.GetWidth(), check_bb.GetHeight());
9446  const float pad = ImMax(1.0f, (float)(int)(check_sz / 6.0f));
9447  RenderCheckMark(check_bb.Min + ImVec2(pad,pad), GetColorU32(ImGuiCol_CheckMark), check_bb.GetWidth() - pad*2.0f);
9448  }
9449 
9450  if (g.LogEnabled)
9451  LogRenderedText(&text_bb.Min, *v ? "[x]" : "[ ]");
9452  if (label_size.x > 0.0f)
9453  RenderText(text_bb.Min, label);
9454 
9455  return pressed;
9456 }
9457 
9458 bool ImGui::CheckboxFlags(const char* label, unsigned int* flags, unsigned int flags_value)
9459 {
9460  bool v = ((*flags & flags_value) == flags_value);
9461  bool pressed = Checkbox(label, &v);
9462  if (pressed)
9463  {
9464  if (v)
9465  *flags |= flags_value;
9466  else
9467  *flags &= ~flags_value;
9468  }
9469 
9470  return pressed;
9471 }
9472 
9473 bool ImGui::RadioButton(const char* label, bool active)
9474 {
9475  ImGuiWindow* window = GetCurrentWindow();
9476  if (window->SkipItems)
9477  return false;
9478 
9479  ImGuiContext& g = *GImGui;
9480  const ImGuiStyle& style = g.Style;
9481  const ImGuiID id = window->GetID(label);
9482  const ImVec2 label_size = CalcTextSize(label, NULL, true);
9483 
9484  const ImRect check_bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(label_size.y + style.FramePadding.y*2-1, label_size.y + style.FramePadding.y*2-1));
9485  ItemSize(check_bb, style.FramePadding.y);
9486 
9487  ImRect total_bb = check_bb;
9488  if (label_size.x > 0)
9489  SameLine(0, style.ItemInnerSpacing.x);
9490  const ImRect text_bb(window->DC.CursorPos + ImVec2(0, style.FramePadding.y), window->DC.CursorPos + ImVec2(0, style.FramePadding.y) + label_size);
9491  if (label_size.x > 0)
9492  {
9493  ItemSize(ImVec2(text_bb.GetWidth(), check_bb.GetHeight()), style.FramePadding.y);
9494  total_bb.Add(text_bb);
9495  }
9496 
9497  if (!ItemAdd(total_bb, id))
9498  return false;
9499 
9500  ImVec2 center = check_bb.GetCenter();
9501  center.x = (float)(int)center.x + 0.5f;
9502  center.y = (float)(int)center.y + 0.5f;
9503  const float radius = check_bb.GetHeight() * 0.5f;
9504 
9505  bool hovered, held;
9506  bool pressed = ButtonBehavior(total_bb, id, &hovered, &held);
9507 
9508  RenderNavHighlight(total_bb, id);
9509  window->DrawList->AddCircleFilled(center, radius, GetColorU32((held && hovered) ? ImGuiCol_FrameBgActive : hovered ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg), 16);
9510  if (active)
9511  {
9512  const float check_sz = ImMin(check_bb.GetWidth(), check_bb.GetHeight());
9513  const float pad = ImMax(1.0f, (float)(int)(check_sz / 6.0f));
9514  window->DrawList->AddCircleFilled(center, radius-pad, GetColorU32(ImGuiCol_CheckMark), 16);
9515  }
9516 
9517  if (style.FrameBorderSize > 0.0f)
9518  {
9519  window->DrawList->AddCircle(center+ImVec2(1,1), radius, GetColorU32(ImGuiCol_BorderShadow), 16, style.FrameBorderSize);
9520  window->DrawList->AddCircle(center, radius, GetColorU32(ImGuiCol_Border), 16, style.FrameBorderSize);
9521  }
9522 
9523  if (g.LogEnabled)
9524  LogRenderedText(&text_bb.Min, active ? "(x)" : "( )");
9525  if (label_size.x > 0.0f)
9526  RenderText(text_bb.Min, label);
9527 
9528  return pressed;
9529 }
9530 
9531 bool ImGui::RadioButton(const char* label, int* v, int v_button)
9532 {
9533  const bool pressed = RadioButton(label, *v == v_button);
9534  if (pressed)
9535  {
9536  *v = v_button;
9537  }
9538  return pressed;
9539 }
9540 
9541 static int InputTextCalcTextLenAndLineCount(const char* text_begin, const char** out_text_end)
9542 {
9543  int line_count = 0;
9544  const char* s = text_begin;
9545  while (char c = *s++) // We are only matching for \n so we can ignore UTF-8 decoding
9546  if (c == '\n')
9547  line_count++;
9548  s--;
9549  if (s[0] != '\n' && s[0] != '\r')
9550  line_count++;
9551  *out_text_end = s;
9552  return line_count;
9553 }
9554 
9555 static ImVec2 InputTextCalcTextSizeW(const ImWchar* text_begin, const ImWchar* text_end, const ImWchar** remaining, ImVec2* out_offset, bool stop_on_new_line)
9556 {
9557  ImFont* font = GImGui->Font;
9558  const float line_height = GImGui->FontSize;
9559  const float scale = line_height / font->FontSize;
9560 
9561  ImVec2 text_size = ImVec2(0,0);
9562  float line_width = 0.0f;
9563 
9564  const ImWchar* s = text_begin;
9565  while (s < text_end)
9566  {
9567  unsigned int c = (unsigned int)(*s++);
9568  if (c == '\n')
9569  {
9570  text_size.x = ImMax(text_size.x, line_width);
9571  text_size.y += line_height;
9572  line_width = 0.0f;
9573  if (stop_on_new_line)
9574  break;
9575  continue;
9576  }
9577  if (c == '\r')
9578  continue;
9579 
9580  const float char_width = font->GetCharAdvance((unsigned short)c) * scale;
9581  line_width += char_width;
9582  }
9583 
9584  if (text_size.x < line_width)
9585  text_size.x = line_width;
9586 
9587  if (out_offset)
9588  *out_offset = ImVec2(line_width, text_size.y + line_height); // offset allow for the possibility of sitting after a trailing \n
9589 
9590  if (line_width > 0 || text_size.y == 0.0f) // whereas size.y will ignore the trailing \n
9591  text_size.y += line_height;
9592 
9593  if (remaining)
9594  *remaining = s;
9595 
9596  return text_size;
9597 }
9598 
9599 // Wrapper for stb_textedit.h to edit text (our wrapper is for: statically sized buffer, single-line, wchar characters. InputText converts between UTF-8 and wchar)
9600 namespace ImGuiStb
9601 {
9602 
9603 static int STB_TEXTEDIT_STRINGLEN(const STB_TEXTEDIT_STRING* obj) { return obj->CurLenW; }
9604 static ImWchar STB_TEXTEDIT_GETCHAR(const STB_TEXTEDIT_STRING* obj, int idx) { return obj->Text[idx]; }
9605 static float STB_TEXTEDIT_GETWIDTH(STB_TEXTEDIT_STRING* obj, int line_start_idx, int char_idx) { ImWchar c = obj->Text[line_start_idx+char_idx]; if (c == '\n') return STB_TEXTEDIT_GETWIDTH_NEWLINE; return GImGui->Font->GetCharAdvance(c) * (GImGui->FontSize / GImGui->Font->FontSize); }
9606 static int STB_TEXTEDIT_KEYTOTEXT(int key) { return key >= 0x10000 ? 0 : key; }
9609 {
9610  const ImWchar* text = obj->Text.Data;
9611  const ImWchar* text_remaining = NULL;
9612  const ImVec2 size = InputTextCalcTextSizeW(text + line_start_idx, text + obj->CurLenW, &text_remaining, NULL, true);
9613  r->x0 = 0.0f;
9614  r->x1 = size.x;
9615  r->baseline_y_delta = size.y;
9616  r->ymin = 0.0f;
9617  r->ymax = size.y;
9618  r->num_chars = (int)(text_remaining - (text + line_start_idx));
9619 }
9620 
9621 static bool is_separator(unsigned int c) { return ImCharIsSpace(c) || c==',' || c==';' || c=='(' || c==')' || c=='{' || c=='}' || c=='[' || c==']' || c=='|'; }
9622 static int is_word_boundary_from_right(STB_TEXTEDIT_STRING* obj, int idx) { return idx > 0 ? (is_separator( obj->Text[idx-1] ) && !is_separator( obj->Text[idx] ) ) : 1; }
9623 static int STB_TEXTEDIT_MOVEWORDLEFT_IMPL(STB_TEXTEDIT_STRING* obj, int idx) { idx--; while (idx >= 0 && !is_word_boundary_from_right(obj, idx)) idx--; return idx < 0 ? 0 : idx; }
9624 #ifdef __APPLE__ // FIXME: Move setting to IO structure
9625 static int is_word_boundary_from_left(STB_TEXTEDIT_STRING* obj, int idx) { return idx > 0 ? (!is_separator( obj->Text[idx-1] ) && is_separator( obj->Text[idx] ) ) : 1; }
9626 static int STB_TEXTEDIT_MOVEWORDRIGHT_IMPL(STB_TEXTEDIT_STRING* obj, int idx) { idx++; int len = obj->CurLenW; while (idx < len && !is_word_boundary_from_left(obj, idx)) idx++; return idx > len ? len : idx; }
9627 #else
9628 static int STB_TEXTEDIT_MOVEWORDRIGHT_IMPL(STB_TEXTEDIT_STRING* obj, int idx) { idx++; int len = obj->CurLenW; while (idx < len && !is_word_boundary_from_right(obj, idx)) idx++; return idx > len ? len : idx; }
9629 #endif
9630 #define STB_TEXTEDIT_MOVEWORDLEFT STB_TEXTEDIT_MOVEWORDLEFT_IMPL // They need to be #define for stb_textedit.h
9631 #define STB_TEXTEDIT_MOVEWORDRIGHT STB_TEXTEDIT_MOVEWORDRIGHT_IMPL
9632 
9634 {
9635  ImWchar* dst = obj->Text.Data + pos;
9636 
9637  // We maintain our buffer length in both UTF-8 and wchar formats
9638  obj->CurLenA -= ImTextCountUtf8BytesFromStr(dst, dst + n);
9639  obj->CurLenW -= n;
9640 
9641  // Offset remaining text
9642  const ImWchar* src = obj->Text.Data + pos + n;
9643  while (ImWchar c = *src++)
9644  *dst++ = c;
9645  *dst = '\0';
9646 }
9647 
9648 static bool STB_TEXTEDIT_INSERTCHARS(STB_TEXTEDIT_STRING* obj, int pos, const ImWchar* new_text, int new_text_len)
9649 {
9650  const int text_len = obj->CurLenW;
9651  IM_ASSERT(pos <= text_len);
9652  if (new_text_len + text_len + 1 > obj->Text.Size)
9653  return false;
9654 
9655  const int new_text_len_utf8 = ImTextCountUtf8BytesFromStr(new_text, new_text + new_text_len);
9656  if (new_text_len_utf8 + obj->CurLenA + 1 > obj->BufSizeA)
9657  return false;
9658 
9659  ImWchar* text = obj->Text.Data;
9660  if (pos != text_len)
9661  memmove(text + pos + new_text_len, text + pos, (size_t)(text_len - pos) * sizeof(ImWchar));
9662  memcpy(text + pos, new_text, (size_t)new_text_len * sizeof(ImWchar));
9663 
9664  obj->CurLenW += new_text_len;
9665  obj->CurLenA += new_text_len_utf8;
9666  obj->Text[obj->CurLenW] = '\0';
9667 
9668  return true;
9669 }
9670 
9671 // We don't use an enum so we can build even with conflicting symbols (if another user of stb_textedit.h leak their STB_TEXTEDIT_K_* symbols)
9672 #define STB_TEXTEDIT_K_LEFT 0x10000 // keyboard input to move cursor left
9673 #define STB_TEXTEDIT_K_RIGHT 0x10001 // keyboard input to move cursor right
9674 #define STB_TEXTEDIT_K_UP 0x10002 // keyboard input to move cursor up
9675 #define STB_TEXTEDIT_K_DOWN 0x10003 // keyboard input to move cursor down
9676 #define STB_TEXTEDIT_K_LINESTART 0x10004 // keyboard input to move cursor to start of line
9677 #define STB_TEXTEDIT_K_LINEEND 0x10005 // keyboard input to move cursor to end of line
9678 #define STB_TEXTEDIT_K_TEXTSTART 0x10006 // keyboard input to move cursor to start of text
9679 #define STB_TEXTEDIT_K_TEXTEND 0x10007 // keyboard input to move cursor to end of text
9680 #define STB_TEXTEDIT_K_DELETE 0x10008 // keyboard input to delete selection or character under cursor
9681 #define STB_TEXTEDIT_K_BACKSPACE 0x10009 // keyboard input to delete selection or character left of cursor
9682 #define STB_TEXTEDIT_K_UNDO 0x1000A // keyboard input to perform undo
9683 #define STB_TEXTEDIT_K_REDO 0x1000B // keyboard input to perform redo
9684 #define STB_TEXTEDIT_K_WORDLEFT 0x1000C // keyboard input to move cursor left one word
9685 #define STB_TEXTEDIT_K_WORDRIGHT 0x1000D // keyboard input to move cursor right one word
9686 #define STB_TEXTEDIT_K_SHIFT 0x20000
9687 
9688 #define STB_TEXTEDIT_IMPLEMENTATION
9690 
9691 }
9692 
9694 {
9695  stb_textedit_key(this, &StbState, key);
9696  CursorFollow = true;
9697  CursorAnimReset();
9698 }
9699 
9700 // Public API to manipulate UTF-8 text
9701 // We expose UTF-8 to the user (unlike the STB_TEXTEDIT_* functions which are manipulating wchar)
9702 // FIXME: The existence of this rarely exercised code path is a bit of a nuisance.
9703 void ImGuiTextEditCallbackData::DeleteChars(int pos, int bytes_count)
9704 {
9705  IM_ASSERT(pos + bytes_count <= BufTextLen);
9706  char* dst = Buf + pos;
9707  const char* src = Buf + pos + bytes_count;
9708  while (char c = *src++)
9709  *dst++ = c;
9710  *dst = '\0';
9711 
9712  if (CursorPos + bytes_count >= pos)
9713  CursorPos -= bytes_count;
9714  else if (CursorPos >= pos)
9715  CursorPos = pos;
9716  SelectionStart = SelectionEnd = CursorPos;
9717  BufDirty = true;
9718  BufTextLen -= bytes_count;
9719 }
9720 
9721 void ImGuiTextEditCallbackData::InsertChars(int pos, const char* new_text, const char* new_text_end)
9722 {
9723  const int new_text_len = new_text_end ? (int)(new_text_end - new_text) : (int)strlen(new_text);
9724  if (new_text_len + BufTextLen + 1 >= BufSize)
9725  return;
9726 
9727  if (BufTextLen != pos)
9728  memmove(Buf + pos + new_text_len, Buf + pos, (size_t)(BufTextLen - pos));
9729  memcpy(Buf + pos, new_text, (size_t)new_text_len * sizeof(char));
9730  Buf[BufTextLen + new_text_len] = '\0';
9731 
9732  if (CursorPos >= pos)
9733  CursorPos += new_text_len;
9734  SelectionStart = SelectionEnd = CursorPos;
9735  BufDirty = true;
9736  BufTextLen += new_text_len;
9737 }
9738 
9739 // Return false to discard a character.
9740 static bool InputTextFilterCharacter(unsigned int* p_char, ImGuiInputTextFlags flags, ImGuiTextEditCallback callback, void* user_data)
9741 {
9742  unsigned int c = *p_char;
9743 
9744  if (c < 128 && c != ' ' && !isprint((int)(c & 0xFF)))
9745  {
9746  bool pass = false;
9747  pass |= (c == '\n' && (flags & ImGuiInputTextFlags_Multiline));
9748  pass |= (c == '\t' && (flags & ImGuiInputTextFlags_AllowTabInput));
9749  if (!pass)
9750  return false;
9751  }
9752 
9753  if (c >= 0xE000 && c <= 0xF8FF) // Filter private Unicode range. I don't imagine anybody would want to input them. GLFW on OSX seems to send private characters for special keys like arrow keys.
9754  return false;
9755 
9757  {
9759  if (!(c >= '0' && c <= '9') && (c != '.') && (c != '-') && (c != '+') && (c != '*') && (c != '/'))
9760  return false;
9761 
9763  if (!(c >= '0' && c <= '9') && !(c >= 'a' && c <= 'f') && !(c >= 'A' && c <= 'F'))
9764  return false;
9765 
9767  if (c >= 'a' && c <= 'z')
9768  *p_char = (c += (unsigned int)('A'-'a'));
9769 
9771  if (ImCharIsSpace(c))
9772  return false;
9773  }
9774 
9776  {
9777  ImGuiTextEditCallbackData callback_data;
9778  memset(&callback_data, 0, sizeof(ImGuiTextEditCallbackData));
9780  callback_data.EventChar = (ImWchar)c;
9781  callback_data.Flags = flags;
9782  callback_data.UserData = user_data;
9783  if (callback(&callback_data) != 0)
9784  return false;
9785  *p_char = callback_data.EventChar;
9786  if (!callback_data.EventChar)
9787  return false;
9788  }
9789 
9790  return true;
9791 }
9792 
9793 // Edit a string of text
9794 // NB: when active, hold on a privately held copy of the text (and apply back to 'buf'). So changing 'buf' while active has no effect.
9795 // FIXME: Rather messy function partly because we are doing UTF8 > u16 > UTF8 conversions on the go to more easily handle stb_textedit calls. Ideally we should stay in UTF-8 all the time. See https://github.com/nothings/stb/issues/188
9796 bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2& size_arg, ImGuiInputTextFlags flags, ImGuiTextEditCallback callback, void* user_data)
9797 {
9798  ImGuiWindow* window = GetCurrentWindow();
9799  if (window->SkipItems)
9800  return false;
9801 
9802  IM_ASSERT(!((flags & ImGuiInputTextFlags_CallbackHistory) && (flags & ImGuiInputTextFlags_Multiline))); // Can't use both together (they both use up/down keys)
9803  IM_ASSERT(!((flags & ImGuiInputTextFlags_CallbackCompletion) && (flags & ImGuiInputTextFlags_AllowTabInput))); // Can't use both together (they both use tab key)
9804 
9805  ImGuiContext& g = *GImGui;
9806  const ImGuiIO& io = g.IO;
9807  const ImGuiStyle& style = g.Style;
9808 
9809  const bool is_multiline = (flags & ImGuiInputTextFlags_Multiline) != 0;
9810  const bool is_editable = (flags & ImGuiInputTextFlags_ReadOnly) == 0;
9811  const bool is_password = (flags & ImGuiInputTextFlags_Password) != 0;
9812  const bool is_undoable = (flags & ImGuiInputTextFlags_NoUndoRedo) == 0;
9813 
9814  if (is_multiline) // Open group before calling GetID() because groups tracks id created during their spawn
9815  BeginGroup();
9816  const ImGuiID id = window->GetID(label);
9817  const ImVec2 label_size = CalcTextSize(label, NULL, true);
9818  ImVec2 size = CalcItemSize(size_arg, CalcItemWidth(), (is_multiline ? GetTextLineHeight() * 8.0f : label_size.y) + style.FramePadding.y*2.0f); // Arbitrary default of 8 lines high for multi-line
9819  const ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + size);
9820  const ImRect total_bb(frame_bb.Min, frame_bb.Max + ImVec2(label_size.x > 0.0f ? (style.ItemInnerSpacing.x + label_size.x) : 0.0f, 0.0f));
9821 
9822  ImGuiWindow* draw_window = window;
9823  if (is_multiline)
9824  {
9825  ItemAdd(total_bb, id, &frame_bb);
9826  if (!BeginChildFrame(id, frame_bb.GetSize()))
9827  {
9828  EndChildFrame();
9829  EndGroup();
9830  return false;
9831  }
9832  draw_window = GetCurrentWindow();
9833  size.x -= draw_window->ScrollbarSizes.x;
9834  }
9835  else
9836  {
9837  ItemSize(total_bb, style.FramePadding.y);
9838  if (!ItemAdd(total_bb, id, &frame_bb))
9839  return false;
9840  }
9841  const bool hovered = ItemHoverable(frame_bb, id);
9842  if (hovered)
9843  g.MouseCursor = ImGuiMouseCursor_TextInput;
9844 
9845  // Password pushes a temporary font with only a fallback glyph
9846  if (is_password)
9847  {
9848  const ImFontGlyph* glyph = g.Font->FindGlyph('*');
9849  ImFont* password_font = &g.InputTextPasswordFont;
9850  password_font->FontSize = g.Font->FontSize;
9851  password_font->Scale = g.Font->Scale;
9852  password_font->DisplayOffset = g.Font->DisplayOffset;
9853  password_font->Ascent = g.Font->Ascent;
9854  password_font->Descent = g.Font->Descent;
9855  password_font->ContainerAtlas = g.Font->ContainerAtlas;
9856  password_font->FallbackGlyph = glyph;
9857  password_font->FallbackAdvanceX = glyph->AdvanceX;
9858  IM_ASSERT(password_font->Glyphs.empty() && password_font->IndexAdvanceX.empty() && password_font->IndexLookup.empty());
9859  PushFont(password_font);
9860  }
9861 
9862  // NB: we are only allowed to access 'edit_state' if we are the active widget.
9863  ImGuiTextEditState& edit_state = g.InputTextState;
9864 
9865  const bool focus_requested = FocusableItemRegister(window, id, (flags & (ImGuiInputTextFlags_CallbackCompletion|ImGuiInputTextFlags_AllowTabInput)) == 0); // Using completion callback disable keyboard tabbing
9866  const bool focus_requested_by_code = focus_requested && (window->FocusIdxAllCounter == window->FocusIdxAllRequestCurrent);
9867  const bool focus_requested_by_tab = focus_requested && !focus_requested_by_code;
9868 
9869  const bool user_clicked = hovered && io.MouseClicked[0];
9870  const bool user_scrolled = is_multiline && g.ActiveId == 0 && edit_state.Id == id && g.ActiveIdPreviousFrame == draw_window->GetIDNoKeepAlive("#SCROLLY");
9871 
9872  bool clear_active_id = false;
9873 
9874  bool select_all = (g.ActiveId != id) && (((flags & ImGuiInputTextFlags_AutoSelectAll) != 0) || (g.NavInputId == id)) && (!is_multiline);
9875  if (focus_requested || user_clicked || user_scrolled || g.NavInputId == id)
9876  {
9877  if (g.ActiveId != id)
9878  {
9879  // Start edition
9880  // Take a copy of the initial buffer value (both in original UTF-8 format and converted to wchar)
9881  // From the moment we focused we are ignoring the content of 'buf' (unless we are in read-only mode)
9882  const int prev_len_w = edit_state.CurLenW;
9883  edit_state.Text.resize(buf_size+1); // wchar count <= UTF-8 count. we use +1 to make sure that .Data isn't NULL so it doesn't crash.
9884  edit_state.InitialText.resize(buf_size+1); // UTF-8. we use +1 to make sure that .Data isn't NULL so it doesn't crash.
9885  ImStrncpy(edit_state.InitialText.Data, buf, edit_state.InitialText.Size);
9886  const char* buf_end = NULL;
9887  edit_state.CurLenW = ImTextStrFromUtf8(edit_state.Text.Data, edit_state.Text.Size, buf, NULL, &buf_end);
9888  edit_state.CurLenA = (int)(buf_end - buf); // We can't get the result from ImFormatString() above because it is not UTF-8 aware. Here we'll cut off malformed UTF-8.
9889  edit_state.CursorAnimReset();
9890 
9891  // Preserve cursor position and undo/redo stack if we come back to same widget
9892  // FIXME: We should probably compare the whole buffer to be on the safety side. Comparing buf (utf8) and edit_state.Text (wchar).
9893  const bool recycle_state = (edit_state.Id == id) && (prev_len_w == edit_state.CurLenW);
9894  if (recycle_state)
9895  {
9896  // Recycle existing cursor/selection/undo stack but clamp position
9897  // Note a single mouse click will override the cursor/position immediately by calling stb_textedit_click handler.
9898  edit_state.CursorClamp();
9899  }
9900  else
9901  {
9902  edit_state.Id = id;
9903  edit_state.ScrollX = 0.0f;
9904  stb_textedit_initialize_state(&edit_state.StbState, !is_multiline);
9905  if (!is_multiline && focus_requested_by_code)
9906  select_all = true;
9907  }
9909  edit_state.StbState.insert_mode = true;
9910  if (!is_multiline && (focus_requested_by_tab || (user_clicked && io.KeyCtrl)))
9911  select_all = true;
9912  }
9913  SetActiveID(id, window);
9914  SetFocusID(id, window);
9915  FocusWindow(window);
9916  if (!is_multiline && !(flags & ImGuiInputTextFlags_CallbackHistory))
9917  g.ActiveIdAllowNavDirFlags |= ((1 << ImGuiDir_Up) | (1 << ImGuiDir_Down));
9918  }
9919  else if (io.MouseClicked[0])
9920  {
9921  // Release focus when we click outside
9922  clear_active_id = true;
9923  }
9924 
9925  bool value_changed = false;
9926  bool enter_pressed = false;
9927 
9928  if (g.ActiveId == id)
9929  {
9930  if (!is_editable && !g.ActiveIdIsJustActivated)
9931  {
9932  // When read-only we always use the live data passed to the function
9933  edit_state.Text.resize(buf_size+1);
9934  const char* buf_end = NULL;
9935  edit_state.CurLenW = ImTextStrFromUtf8(edit_state.Text.Data, edit_state.Text.Size, buf, NULL, &buf_end);
9936  edit_state.CurLenA = (int)(buf_end - buf);
9937  edit_state.CursorClamp();
9938  }
9939 
9940  edit_state.BufSizeA = buf_size;
9941 
9942  // Although we are active we don't prevent mouse from hovering other elements unless we are interacting right now with the widget.
9943  // Down the line we should have a cleaner library-wide concept of Selected vs Active.
9944  g.ActiveIdAllowOverlap = !io.MouseDown[0];
9945  g.WantTextInputNextFrame = 1;
9946 
9947  // Edit in progress
9948  const float mouse_x = (io.MousePos.x - frame_bb.Min.x - style.FramePadding.x) + edit_state.ScrollX;
9949  const float mouse_y = (is_multiline ? (io.MousePos.y - draw_window->DC.CursorPos.y - style.FramePadding.y) : (g.FontSize*0.5f));
9950 
9951  const bool osx_double_click_selects_words = io.OptMacOSXBehaviors; // OS X style: Double click selects by word instead of selecting whole text
9952  if (select_all || (hovered && !osx_double_click_selects_words && io.MouseDoubleClicked[0]))
9953  {
9954  edit_state.SelectAll();
9955  edit_state.SelectedAllMouseLock = true;
9956  }
9957  else if (hovered && osx_double_click_selects_words && io.MouseDoubleClicked[0])
9958  {
9959  // Select a word only, OS X style (by simulating keystrokes)
9962  }
9963  else if (io.MouseClicked[0] && !edit_state.SelectedAllMouseLock)
9964  {
9965  if (hovered)
9966  {
9967  stb_textedit_click(&edit_state, &edit_state.StbState, mouse_x, mouse_y);
9968  edit_state.CursorAnimReset();
9969  }
9970  }
9971  else if (io.MouseDown[0] && !edit_state.SelectedAllMouseLock && (io.MouseDelta.x != 0.0f || io.MouseDelta.y != 0.0f))
9972  {
9973  stb_textedit_drag(&edit_state, &edit_state.StbState, mouse_x, mouse_y);
9974  edit_state.CursorAnimReset();
9975  edit_state.CursorFollow = true;
9976  }
9977  if (edit_state.SelectedAllMouseLock && !io.MouseDown[0])
9978  edit_state.SelectedAllMouseLock = false;
9979 
9980  if (io.InputCharacters[0])
9981  {
9982  // Process text input (before we check for Return because using some IME will effectively send a Return?)
9983  // We ignore CTRL inputs, but need to allow CTRL+ALT as some keyboards (e.g. German) use AltGR - which is Alt+Ctrl - to input certain characters.
9984  if (!(io.KeyCtrl && !io.KeyAlt) && is_editable)
9985  {
9986  for (int n = 0; n < IM_ARRAYSIZE(io.InputCharacters) && io.InputCharacters[n]; n++)
9987  if (unsigned int c = (unsigned int)io.InputCharacters[n])
9988  {
9989  // Insert character if they pass filtering
9990  if (!InputTextFilterCharacter(&c, flags, callback, user_data))
9991  continue;
9992  edit_state.OnKeyPressed((int)c);
9993  }
9994  }
9995 
9996  // Consume characters
9997  memset(g.IO.InputCharacters, 0, sizeof(g.IO.InputCharacters));
9998  }
9999  }
10000 
10001  bool cancel_edit = false;
10002  if (g.ActiveId == id && !g.ActiveIdIsJustActivated && !clear_active_id)
10003  {
10004  // Handle key-presses
10005  const int k_mask = (io.KeyShift ? STB_TEXTEDIT_K_SHIFT : 0);
10006  const bool is_shortcut_key_only = (io.OptMacOSXBehaviors ? (io.KeySuper && !io.KeyCtrl) : (io.KeyCtrl && !io.KeySuper)) && !io.KeyAlt && !io.KeyShift; // OS X style: Shortcuts using Cmd/Super instead of Ctrl
10007  const bool is_wordmove_key_down = io.OptMacOSXBehaviors ? io.KeyAlt : io.KeyCtrl; // OS X style: Text editing cursor movement using Alt instead of Ctrl
10008  const bool is_startend_key_down = io.OptMacOSXBehaviors && io.KeySuper && !io.KeyCtrl && !io.KeyAlt; // OS X style: Line/Text Start and End using Cmd+Arrows instead of Home/End
10009  const bool is_ctrl_key_only = io.KeyCtrl && !io.KeyShift && !io.KeyAlt && !io.KeySuper;
10010  const bool is_shift_key_only = io.KeyShift && !io.KeyCtrl && !io.KeyAlt && !io.KeySuper;
10011 
10012  const bool is_cut = ((is_shortcut_key_only && IsKeyPressedMap(ImGuiKey_X)) || (is_shift_key_only && IsKeyPressedMap(ImGuiKey_Delete))) && is_editable && !is_password && (!is_multiline || edit_state.HasSelection());
10013  const bool is_copy = ((is_shortcut_key_only && IsKeyPressedMap(ImGuiKey_C)) || (is_ctrl_key_only && IsKeyPressedMap(ImGuiKey_Insert))) && !is_password && (!is_multiline || edit_state.HasSelection());
10014  const bool is_paste = ((is_shortcut_key_only && IsKeyPressedMap(ImGuiKey_V)) || (is_shift_key_only && IsKeyPressedMap(ImGuiKey_Insert))) && is_editable;
10015 
10016  if (IsKeyPressedMap(ImGuiKey_LeftArrow)) { edit_state.OnKeyPressed((is_startend_key_down ? STB_TEXTEDIT_K_LINESTART : is_wordmove_key_down ? STB_TEXTEDIT_K_WORDLEFT : STB_TEXTEDIT_K_LEFT) | k_mask); }
10017  else if (IsKeyPressedMap(ImGuiKey_RightArrow)) { edit_state.OnKeyPressed((is_startend_key_down ? STB_TEXTEDIT_K_LINEEND : is_wordmove_key_down ? STB_TEXTEDIT_K_WORDRIGHT : STB_TEXTEDIT_K_RIGHT) | k_mask); }
10018  else if (IsKeyPressedMap(ImGuiKey_UpArrow) && is_multiline) { if (io.KeyCtrl) SetWindowScrollY(draw_window, ImMax(draw_window->Scroll.y - g.FontSize, 0.0f)); else edit_state.OnKeyPressed((is_startend_key_down ? STB_TEXTEDIT_K_TEXTSTART : STB_TEXTEDIT_K_UP) | k_mask); }
10019  else if (IsKeyPressedMap(ImGuiKey_DownArrow) && is_multiline) { if (io.KeyCtrl) SetWindowScrollY(draw_window, ImMin(draw_window->Scroll.y + g.FontSize, GetScrollMaxY())); else edit_state.OnKeyPressed((is_startend_key_down ? STB_TEXTEDIT_K_TEXTEND : STB_TEXTEDIT_K_DOWN) | k_mask); }
10020  else if (IsKeyPressedMap(ImGuiKey_Home)) { edit_state.OnKeyPressed(io.KeyCtrl ? STB_TEXTEDIT_K_TEXTSTART | k_mask : STB_TEXTEDIT_K_LINESTART | k_mask); }
10021  else if (IsKeyPressedMap(ImGuiKey_End)) { edit_state.OnKeyPressed(io.KeyCtrl ? STB_TEXTEDIT_K_TEXTEND | k_mask : STB_TEXTEDIT_K_LINEEND | k_mask); }
10022  else if (IsKeyPressedMap(ImGuiKey_Delete) && is_editable) { edit_state.OnKeyPressed(STB_TEXTEDIT_K_DELETE | k_mask); }
10023  else if (IsKeyPressedMap(ImGuiKey_Backspace) && is_editable)
10024  {
10025  if (!edit_state.HasSelection())
10026  {
10027  if (is_wordmove_key_down) edit_state.OnKeyPressed(STB_TEXTEDIT_K_WORDLEFT|STB_TEXTEDIT_K_SHIFT);
10029  }
10030  edit_state.OnKeyPressed(STB_TEXTEDIT_K_BACKSPACE | k_mask);
10031  }
10032  else if (IsKeyPressedMap(ImGuiKey_Enter))
10033  {
10034  bool ctrl_enter_for_new_line = (flags & ImGuiInputTextFlags_CtrlEnterForNewLine) != 0;
10035  if (!is_multiline || (ctrl_enter_for_new_line && !io.KeyCtrl) || (!ctrl_enter_for_new_line && io.KeyCtrl))
10036  {
10037  enter_pressed = clear_active_id = true;
10038  }
10039  else if (is_editable)
10040  {
10041  unsigned int c = '\n'; // Insert new line
10042  if (InputTextFilterCharacter(&c, flags, callback, user_data))
10043  edit_state.OnKeyPressed((int)c);
10044  }
10045  }
10046  else if ((flags & ImGuiInputTextFlags_AllowTabInput) && IsKeyPressedMap(ImGuiKey_Tab) && !io.KeyCtrl && !io.KeyShift && !io.KeyAlt && is_editable)
10047  {
10048  unsigned int c = '\t'; // Insert TAB
10049  if (InputTextFilterCharacter(&c, flags, callback, user_data))
10050  edit_state.OnKeyPressed((int)c);
10051  }
10052  else if (IsKeyPressedMap(ImGuiKey_Escape)) { clear_active_id = cancel_edit = true; }
10053  else if (is_shortcut_key_only && IsKeyPressedMap(ImGuiKey_Z) && is_editable && is_undoable) { edit_state.OnKeyPressed(STB_TEXTEDIT_K_UNDO); edit_state.ClearSelection(); }
10054  else if (is_shortcut_key_only && IsKeyPressedMap(ImGuiKey_Y) && is_editable && is_undoable) { edit_state.OnKeyPressed(STB_TEXTEDIT_K_REDO); edit_state.ClearSelection(); }
10055  else if (is_shortcut_key_only && IsKeyPressedMap(ImGuiKey_A)) { edit_state.SelectAll(); edit_state.CursorFollow = true; }
10056  else if (is_cut || is_copy)
10057  {
10058  // Cut, Copy
10059  if (io.SetClipboardTextFn)
10060  {
10061  const int ib = edit_state.HasSelection() ? ImMin(edit_state.StbState.select_start, edit_state.StbState.select_end) : 0;
10062  const int ie = edit_state.HasSelection() ? ImMax(edit_state.StbState.select_start, edit_state.StbState.select_end) : edit_state.CurLenW;
10063  edit_state.TempTextBuffer.resize((ie-ib) * 4 + 1);
10064  ImTextStrToUtf8(edit_state.TempTextBuffer.Data, edit_state.TempTextBuffer.Size, edit_state.Text.Data+ib, edit_state.Text.Data+ie);
10065  SetClipboardText(edit_state.TempTextBuffer.Data);
10066  }
10067 
10068  if (is_cut)
10069  {
10070  if (!edit_state.HasSelection())
10071  edit_state.SelectAll();
10072  edit_state.CursorFollow = true;
10073  stb_textedit_cut(&edit_state, &edit_state.StbState);
10074  }
10075  }
10076  else if (is_paste)
10077  {
10078  // Paste
10079  if (const char* clipboard = GetClipboardText())
10080  {
10081  // Filter pasted buffer
10082  const int clipboard_len = (int)strlen(clipboard);
10083  ImWchar* clipboard_filtered = (ImWchar*)ImGui::MemAlloc((clipboard_len+1) * sizeof(ImWchar));
10084  int clipboard_filtered_len = 0;
10085  for (const char* s = clipboard; *s; )
10086  {
10087  unsigned int c;
10088  s += ImTextCharFromUtf8(&c, s, NULL);
10089  if (c == 0)
10090  break;
10091  if (c >= 0x10000 || !InputTextFilterCharacter(&c, flags, callback, user_data))
10092  continue;
10093  clipboard_filtered[clipboard_filtered_len++] = (ImWchar)c;
10094  }
10095  clipboard_filtered[clipboard_filtered_len] = 0;
10096  if (clipboard_filtered_len > 0) // If everything was filtered, ignore the pasting operation
10097  {
10098  stb_textedit_paste(&edit_state, &edit_state.StbState, clipboard_filtered, clipboard_filtered_len);
10099  edit_state.CursorFollow = true;
10100  }
10101  ImGui::MemFree(clipboard_filtered);
10102  }
10103  }
10104  }
10105 
10106  if (g.ActiveId == id)
10107  {
10108  if (cancel_edit)
10109  {
10110  // Restore initial value
10111  if (is_editable)
10112  {
10113  ImStrncpy(buf, edit_state.InitialText.Data, buf_size);
10114  value_changed = true;
10115  }
10116  }
10117 
10118  // When using 'ImGuiInputTextFlags_EnterReturnsTrue' as a special case we reapply the live buffer back to the input buffer before clearing ActiveId, even though strictly speaking it wasn't modified on this frame.
10119  // If we didn't do that, code like InputInt() with ImGuiInputTextFlags_EnterReturnsTrue would fail. Also this allows the user to use InputText() with ImGuiInputTextFlags_EnterReturnsTrue without maintaining any user-side storage.
10120  bool apply_edit_back_to_user_buffer = !cancel_edit || (enter_pressed && (flags & ImGuiInputTextFlags_EnterReturnsTrue) != 0);
10121  if (apply_edit_back_to_user_buffer)
10122  {
10123  // Apply new value immediately - copy modified buffer back
10124  // Note that as soon as the input box is active, the in-widget value gets priority over any underlying modification of the input buffer
10125  // FIXME: We actually always render 'buf' when calling DrawList->AddText, making the comment above incorrect.
10126  // FIXME-OPT: CPU waste to do this every time the widget is active, should mark dirty state from the stb_textedit callbacks.
10127  if (is_editable)
10128  {
10129  edit_state.TempTextBuffer.resize(edit_state.Text.Size * 4);
10130  ImTextStrToUtf8(edit_state.TempTextBuffer.Data, edit_state.TempTextBuffer.Size, edit_state.Text.Data, NULL);
10131  }
10132 
10133  // User callback
10135  {
10136  IM_ASSERT(callback != NULL);
10137 
10138  // The reason we specify the usage semantic (Completion/History) is that Completion needs to disable keyboard TABBING at the moment.
10139  ImGuiInputTextFlags event_flag = 0;
10140  ImGuiKey event_key = ImGuiKey_COUNT;
10142  {
10144  event_key = ImGuiKey_Tab;
10145  }
10147  {
10149  event_key = ImGuiKey_UpArrow;
10150  }
10152  {
10154  event_key = ImGuiKey_DownArrow;
10155  }
10158 
10159  if (event_flag)
10160  {
10161  ImGuiTextEditCallbackData callback_data;
10162  memset(&callback_data, 0, sizeof(ImGuiTextEditCallbackData));
10163  callback_data.EventFlag = event_flag;
10164  callback_data.Flags = flags;
10165  callback_data.UserData = user_data;
10166  callback_data.ReadOnly = !is_editable;
10167 
10168  callback_data.EventKey = event_key;
10169  callback_data.Buf = edit_state.TempTextBuffer.Data;
10170  callback_data.BufTextLen = edit_state.CurLenA;
10171  callback_data.BufSize = edit_state.BufSizeA;
10172  callback_data.BufDirty = false;
10173 
10174  // We have to convert from wchar-positions to UTF-8-positions, which can be pretty slow (an incentive to ditch the ImWchar buffer, see https://github.com/nothings/stb/issues/188)
10175  ImWchar* text = edit_state.Text.Data;
10176  const int utf8_cursor_pos = callback_data.CursorPos = ImTextCountUtf8BytesFromStr(text, text + edit_state.StbState.cursor);
10177  const int utf8_selection_start = callback_data.SelectionStart = ImTextCountUtf8BytesFromStr(text, text + edit_state.StbState.select_start);
10178  const int utf8_selection_end = callback_data.SelectionEnd = ImTextCountUtf8BytesFromStr(text, text + edit_state.StbState.select_end);
10179 
10180  // Call user code
10181  callback(&callback_data);
10182 
10183  // Read back what user may have modified
10184  IM_ASSERT(callback_data.Buf == edit_state.TempTextBuffer.Data); // Invalid to modify those fields
10185  IM_ASSERT(callback_data.BufSize == edit_state.BufSizeA);
10186  IM_ASSERT(callback_data.Flags == flags);
10187  if (callback_data.CursorPos != utf8_cursor_pos) edit_state.StbState.cursor = ImTextCountCharsFromUtf8(callback_data.Buf, callback_data.Buf + callback_data.CursorPos);
10188  if (callback_data.SelectionStart != utf8_selection_start) edit_state.StbState.select_start = ImTextCountCharsFromUtf8(callback_data.Buf, callback_data.Buf + callback_data.SelectionStart);
10189  if (callback_data.SelectionEnd != utf8_selection_end) edit_state.StbState.select_end = ImTextCountCharsFromUtf8(callback_data.Buf, callback_data.Buf + callback_data.SelectionEnd);
10190  if (callback_data.BufDirty)
10191  {
10192  IM_ASSERT(callback_data.BufTextLen == (int)strlen(callback_data.Buf)); // You need to maintain BufTextLen if you change the text!
10193  edit_state.CurLenW = ImTextStrFromUtf8(edit_state.Text.Data, edit_state.Text.Size, callback_data.Buf, NULL);
10194  edit_state.CurLenA = callback_data.BufTextLen; // Assume correct length and valid UTF-8 from user, saves us an extra strlen()
10195  edit_state.CursorAnimReset();
10196  }
10197  }
10198  }
10199 
10200  // Copy back to user buffer
10201  if (is_editable && strcmp(edit_state.TempTextBuffer.Data, buf) != 0)
10202  {
10203  ImStrncpy(buf, edit_state.TempTextBuffer.Data, buf_size);
10204  value_changed = true;
10205  }
10206  }
10207  }
10208 
10209  // Release active ID at the end of the function (so e.g. pressing Return still does a final application of the value)
10210  if (clear_active_id && g.ActiveId == id)
10211  ClearActiveID();
10212 
10213  // Render
10214  // Select which buffer we are going to display. When ImGuiInputTextFlags_NoLiveEdit is set 'buf' might still be the old value. We set buf to NULL to prevent accidental usage from now on.
10215  const char* buf_display = (g.ActiveId == id && is_editable) ? edit_state.TempTextBuffer.Data : buf; buf = NULL;
10216 
10217  RenderNavHighlight(frame_bb, id);
10218  if (!is_multiline)
10219  RenderFrame(frame_bb.Min, frame_bb.Max, GetColorU32(ImGuiCol_FrameBg), true, style.FrameRounding);
10220 
10221  const ImVec4 clip_rect(frame_bb.Min.x, frame_bb.Min.y, frame_bb.Min.x + size.x, frame_bb.Min.y + size.y); // Not using frame_bb.Max because we have adjusted size
10222  ImVec2 render_pos = is_multiline ? draw_window->DC.CursorPos : frame_bb.Min + style.FramePadding;
10223  ImVec2 text_size(0.f, 0.f);
10224  const bool is_currently_scrolling = (edit_state.Id == id && is_multiline && g.ActiveId == draw_window->GetIDNoKeepAlive("#SCROLLY"));
10225  if (g.ActiveId == id || is_currently_scrolling)
10226  {
10227  edit_state.CursorAnim += io.DeltaTime;
10228 
10229  // This is going to be messy. We need to:
10230  // - Display the text (this alone can be more easily clipped)
10231  // - Handle scrolling, highlight selection, display cursor (those all requires some form of 1d->2d cursor position calculation)
10232  // - Measure text height (for scrollbar)
10233  // We are attempting to do most of that in **one main pass** to minimize the computation cost (non-negligible for large amount of text) + 2nd pass for selection rendering (we could merge them by an extra refactoring effort)
10234  // FIXME: This should occur on buf_display but we'd need to maintain cursor/select_start/select_end for UTF-8.
10235  const ImWchar* text_begin = edit_state.Text.Data;
10236  ImVec2 cursor_offset, select_start_offset;
10237 
10238  {
10239  // Count lines + find lines numbers straddling 'cursor' and 'select_start' position.
10240  const ImWchar* searches_input_ptr[2];
10241  searches_input_ptr[0] = text_begin + edit_state.StbState.cursor;
10242  searches_input_ptr[1] = NULL;
10243  int searches_remaining = 1;
10244  int searches_result_line_number[2] = { -1, -999 };
10245  if (edit_state.StbState.select_start != edit_state.StbState.select_end)
10246  {
10247  searches_input_ptr[1] = text_begin + ImMin(edit_state.StbState.select_start, edit_state.StbState.select_end);
10248  searches_result_line_number[1] = -1;
10249  searches_remaining++;
10250  }
10251 
10252  // Iterate all lines to find our line numbers
10253  // In multi-line mode, we never exit the loop until all lines are counted, so add one extra to the searches_remaining counter.
10254  searches_remaining += is_multiline ? 1 : 0;
10255  int line_count = 0;
10256  for (const ImWchar* s = text_begin; *s != 0; s++)
10257  if (*s == '\n')
10258  {
10259  line_count++;
10260  if (searches_result_line_number[0] == -1 && s >= searches_input_ptr[0]) { searches_result_line_number[0] = line_count; if (--searches_remaining <= 0) break; }
10261  if (searches_result_line_number[1] == -1 && s >= searches_input_ptr[1]) { searches_result_line_number[1] = line_count; if (--searches_remaining <= 0) break; }
10262  }
10263  line_count++;
10264  if (searches_result_line_number[0] == -1) searches_result_line_number[0] = line_count;
10265  if (searches_result_line_number[1] == -1) searches_result_line_number[1] = line_count;
10266 
10267  // Calculate 2d position by finding the beginning of the line and measuring distance
10268  cursor_offset.x = InputTextCalcTextSizeW(ImStrbolW(searches_input_ptr[0], text_begin), searches_input_ptr[0]).x;
10269  cursor_offset.y = searches_result_line_number[0] * g.FontSize;
10270  if (searches_result_line_number[1] >= 0)
10271  {
10272  select_start_offset.x = InputTextCalcTextSizeW(ImStrbolW(searches_input_ptr[1], text_begin), searches_input_ptr[1]).x;
10273  select_start_offset.y = searches_result_line_number[1] * g.FontSize;
10274  }
10275 
10276  // Store text height (note that we haven't calculated text width at all, see GitHub issues #383, #1224)
10277  if (is_multiline)
10278  text_size = ImVec2(size.x, line_count * g.FontSize);
10279  }
10280 
10281  // Scroll
10282  if (edit_state.CursorFollow)
10283  {
10284  // Horizontal scroll in chunks of quarter width
10286  {
10287  const float scroll_increment_x = size.x * 0.25f;
10288  if (cursor_offset.x < edit_state.ScrollX)
10289  edit_state.ScrollX = (float)(int)ImMax(0.0f, cursor_offset.x - scroll_increment_x);
10290  else if (cursor_offset.x - size.x >= edit_state.ScrollX)
10291  edit_state.ScrollX = (float)(int)(cursor_offset.x - size.x + scroll_increment_x);
10292  }
10293  else
10294  {
10295  edit_state.ScrollX = 0.0f;
10296  }
10297 
10298  // Vertical scroll
10299  if (is_multiline)
10300  {
10301  float scroll_y = draw_window->Scroll.y;
10302  if (cursor_offset.y - g.FontSize < scroll_y)
10303  scroll_y = ImMax(0.0f, cursor_offset.y - g.FontSize);
10304  else if (cursor_offset.y - size.y >= scroll_y)
10305  scroll_y = cursor_offset.y - size.y;
10306  draw_window->DC.CursorPos.y += (draw_window->Scroll.y - scroll_y); // To avoid a frame of lag
10307  draw_window->Scroll.y = scroll_y;
10308  render_pos.y = draw_window->DC.CursorPos.y;
10309  }
10310  }
10311  edit_state.CursorFollow = false;
10312  const ImVec2 render_scroll = ImVec2(edit_state.ScrollX, 0.0f);
10313 
10314  // Draw selection
10315  if (edit_state.StbState.select_start != edit_state.StbState.select_end)
10316  {
10317  const ImWchar* text_selected_begin = text_begin + ImMin(edit_state.StbState.select_start, edit_state.StbState.select_end);
10318  const ImWchar* text_selected_end = text_begin + ImMax(edit_state.StbState.select_start, edit_state.StbState.select_end);
10319 
10320  float bg_offy_up = is_multiline ? 0.0f : -1.0f; // FIXME: those offsets should be part of the style? they don't play so well with multi-line selection.
10321  float bg_offy_dn = is_multiline ? 0.0f : 2.0f;
10323  ImVec2 rect_pos = render_pos + select_start_offset - render_scroll;
10324  for (const ImWchar* p = text_selected_begin; p < text_selected_end; )
10325  {
10326  if (rect_pos.y > clip_rect.w + g.FontSize)
10327  break;
10328  if (rect_pos.y < clip_rect.y)
10329  {
10330  while (p < text_selected_end)
10331  if (*p++ == '\n')
10332  break;
10333  }
10334  else
10335  {
10336  ImVec2 rect_size = InputTextCalcTextSizeW(p, text_selected_end, &p, NULL, true);
10337  if (rect_size.x <= 0.0f) rect_size.x = (float)(int)(g.Font->GetCharAdvance((unsigned short)' ') * 0.50f); // So we can see selected empty lines
10338  ImRect rect(rect_pos + ImVec2(0.0f, bg_offy_up - g.FontSize), rect_pos +ImVec2(rect_size.x, bg_offy_dn));
10339  rect.ClipWith(clip_rect);
10340  if (rect.Overlaps(clip_rect))
10341  draw_window->DrawList->AddRectFilled(rect.Min, rect.Max, bg_color);
10342  }
10343  rect_pos.x = render_pos.x - render_scroll.x;
10344  rect_pos.y += g.FontSize;
10345  }
10346  }
10347 
10348  draw_window->DrawList->AddText(g.Font, g.FontSize, render_pos - render_scroll, GetColorU32(ImGuiCol_Text), buf_display, buf_display + edit_state.CurLenA, 0.0f, is_multiline ? NULL : &clip_rect);
10349 
10350  // Draw blinking cursor
10351  bool cursor_is_visible = (!g.IO.OptCursorBlink) || (g.InputTextState.CursorAnim <= 0.0f) || fmodf(g.InputTextState.CursorAnim, 1.20f) <= 0.80f;
10352  ImVec2 cursor_screen_pos = render_pos + cursor_offset - render_scroll;
10353  ImRect cursor_screen_rect(cursor_screen_pos.x, cursor_screen_pos.y-g.FontSize+0.5f, cursor_screen_pos.x+1.0f, cursor_screen_pos.y-1.5f);
10354  if (cursor_is_visible && cursor_screen_rect.Overlaps(clip_rect))
10355  draw_window->DrawList->AddLine(cursor_screen_rect.Min, cursor_screen_rect.GetBL(), GetColorU32(ImGuiCol_Text));
10356 
10357  // Notify OS of text input position for advanced IME (-1 x offset so that Windows IME can cover our cursor. Bit of an extra nicety.)
10358  if (is_editable)
10359  g.OsImePosRequest = ImVec2(cursor_screen_pos.x - 1, cursor_screen_pos.y - g.FontSize);
10360  }
10361  else
10362  {
10363  // Render text only
10364  const char* buf_end = NULL;
10365  if (is_multiline)
10366  text_size = ImVec2(size.x, InputTextCalcTextLenAndLineCount(buf_display, &buf_end) * g.FontSize); // We don't need width
10367  draw_window->DrawList->AddText(g.Font, g.FontSize, render_pos, GetColorU32(ImGuiCol_Text), buf_display, buf_end, 0.0f, is_multiline ? NULL : &clip_rect);
10368  }
10369 
10370  if (is_multiline)
10371  {
10372  Dummy(text_size + ImVec2(0.0f, g.FontSize)); // Always add room to scroll an extra line
10373  EndChildFrame();
10374  EndGroup();
10375  }
10376 
10377  if (is_password)
10378  PopFont();
10379 
10380  // Log as text
10381  if (g.LogEnabled && !is_password)
10382  LogRenderedText(&render_pos, buf_display, NULL);
10383 
10384  if (label_size.x > 0)
10385  RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, frame_bb.Min.y + style.FramePadding.y), label);
10386 
10388  return enter_pressed;
10389  else
10390  return value_changed;
10391 }
10392 
10393 bool ImGui::InputText(const char* label, char* buf, size_t buf_size, ImGuiInputTextFlags flags, ImGuiTextEditCallback callback, void* user_data)
10394 {
10395  IM_ASSERT(!(flags & ImGuiInputTextFlags_Multiline)); // call InputTextMultiline()
10396  return InputTextEx(label, buf, (int)buf_size, ImVec2(0,0), flags, callback, user_data);
10397 }
10398 
10399 bool ImGui::InputTextMultiline(const char* label, char* buf, size_t buf_size, const ImVec2& size, ImGuiInputTextFlags flags, ImGuiTextEditCallback callback, void* user_data)
10400 {
10401  return InputTextEx(label, buf, (int)buf_size, size, flags | ImGuiInputTextFlags_Multiline, callback, user_data);
10402 }
10403 
10404 // NB: scalar_format here must be a simple "%xx" format string with no prefix/suffix (unlike the Drag/Slider functions "display_format" argument)
10405 bool ImGui::InputScalarEx(const char* label, ImGuiDataType data_type, void* data_ptr, void* step_ptr, void* step_fast_ptr, const char* scalar_format, ImGuiInputTextFlags extra_flags)
10406 {
10407  ImGuiWindow* window = GetCurrentWindow();
10408  if (window->SkipItems)
10409  return false;
10410 
10411  ImGuiContext& g = *GImGui;
10412  const ImGuiStyle& style = g.Style;
10413  const ImVec2 label_size = CalcTextSize(label, NULL, true);
10414 
10415  BeginGroup();
10416  PushID(label);
10417  const ImVec2 button_sz = ImVec2(GetFrameHeight(), GetFrameHeight());
10418  if (step_ptr)
10419  PushItemWidth(ImMax(1.0f, CalcItemWidth() - (button_sz.x + style.ItemInnerSpacing.x)*2));
10420 
10421  char buf[64];
10422  DataTypeFormatString(data_type, data_ptr, scalar_format, buf, IM_ARRAYSIZE(buf));
10423 
10424  bool value_changed = false;
10425  if (!(extra_flags & ImGuiInputTextFlags_CharsHexadecimal))
10426  extra_flags |= ImGuiInputTextFlags_CharsDecimal;
10427  extra_flags |= ImGuiInputTextFlags_AutoSelectAll;
10428  if (InputText("", buf, IM_ARRAYSIZE(buf), extra_flags)) // PushId(label) + "" gives us the expected ID from outside point of view
10429  value_changed = DataTypeApplyOpFromText(buf, GImGui->InputTextState.InitialText.begin(), data_type, data_ptr, scalar_format);
10430 
10431  // Step buttons
10432  if (step_ptr)
10433  {
10434  PopItemWidth();
10435  SameLine(0, style.ItemInnerSpacing.x);
10437  {
10438  DataTypeApplyOp(data_type, '-', data_ptr, g.IO.KeyCtrl && step_fast_ptr ? step_fast_ptr : step_ptr);
10439  value_changed = true;
10440  }
10441  SameLine(0, style.ItemInnerSpacing.x);
10443  {
10444  DataTypeApplyOp(data_type, '+', data_ptr, g.IO.KeyCtrl && step_fast_ptr ? step_fast_ptr : step_ptr);
10445  value_changed = true;
10446  }
10447  }
10448  PopID();
10449 
10450  if (label_size.x > 0)
10451  {
10452  SameLine(0, style.ItemInnerSpacing.x);
10453  RenderText(ImVec2(window->DC.CursorPos.x, window->DC.CursorPos.y + style.FramePadding.y), label);
10454  ItemSize(label_size, style.FramePadding.y);
10455  }
10456  EndGroup();
10457 
10458  return value_changed;
10459 }
10460 
10461 bool ImGui::InputFloat(const char* label, float* v, float step, float step_fast, int decimal_precision, ImGuiInputTextFlags extra_flags)
10462 {
10463  char display_format[16];
10464  if (decimal_precision < 0)
10465  strcpy(display_format, "%f"); // Ideally we'd have a minimum decimal precision of 1 to visually denote that this is a float, while hiding non-significant digits? %f doesn't have a minimum of 1
10466  else
10467  ImFormatString(display_format, IM_ARRAYSIZE(display_format), "%%.%df", decimal_precision);
10468  return InputScalarEx(label, ImGuiDataType_Float, (void*)v, (void*)(step>0.0f ? &step : NULL), (void*)(step_fast>0.0f ? &step_fast : NULL), display_format, extra_flags);
10469 }
10470 
10471 bool ImGui::InputInt(const char* label, int* v, int step, int step_fast, ImGuiInputTextFlags extra_flags)
10472 {
10473  // Hexadecimal input provided as a convenience but the flag name is awkward. Typically you'd use InputText() to parse your own data, if you want to handle prefixes.
10474  const char* scalar_format = (extra_flags & ImGuiInputTextFlags_CharsHexadecimal) ? "%08X" : "%d";
10475  return InputScalarEx(label, ImGuiDataType_Int, (void*)v, (void*)(step>0.0f ? &step : NULL), (void*)(step_fast>0.0f ? &step_fast : NULL), scalar_format, extra_flags);
10476 }
10477 
10478 bool ImGui::InputFloatN(const char* label, float* v, int components, int decimal_precision, ImGuiInputTextFlags extra_flags)
10479 {
10480  ImGuiWindow* window = GetCurrentWindow();
10481  if (window->SkipItems)
10482  return false;
10483 
10484  ImGuiContext& g = *GImGui;
10485  bool value_changed = false;
10486  BeginGroup();
10487  PushID(label);
10489  for (int i = 0; i < components; i++)
10490  {
10491  PushID(i);
10492  value_changed |= InputFloat("##v", &v[i], 0, 0, decimal_precision, extra_flags);
10493  SameLine(0, g.Style.ItemInnerSpacing.x);
10494  PopID();
10495  PopItemWidth();
10496  }
10497  PopID();
10498 
10500  EndGroup();
10501 
10502  return value_changed;
10503 }
10504 
10505 bool ImGui::InputFloat2(const char* label, float v[2], int decimal_precision, ImGuiInputTextFlags extra_flags)
10506 {
10507  return InputFloatN(label, v, 2, decimal_precision, extra_flags);
10508 }
10509 
10510 bool ImGui::InputFloat3(const char* label, float v[3], int decimal_precision, ImGuiInputTextFlags extra_flags)
10511 {
10512  return InputFloatN(label, v, 3, decimal_precision, extra_flags);
10513 }
10514 
10515 bool ImGui::InputFloat4(const char* label, float v[4], int decimal_precision, ImGuiInputTextFlags extra_flags)
10516 {
10517  return InputFloatN(label, v, 4, decimal_precision, extra_flags);
10518 }
10519 
10520 bool ImGui::InputIntN(const char* label, int* v, int components, ImGuiInputTextFlags extra_flags)
10521 {
10522  ImGuiWindow* window = GetCurrentWindow();
10523  if (window->SkipItems)
10524  return false;
10525 
10526  ImGuiContext& g = *GImGui;
10527  bool value_changed = false;
10528  BeginGroup();
10529  PushID(label);
10531  for (int i = 0; i < components; i++)
10532  {
10533  PushID(i);
10534  value_changed |= InputInt("##v", &v[i], 0, 0, extra_flags);
10535  SameLine(0, g.Style.ItemInnerSpacing.x);
10536  PopID();
10537  PopItemWidth();
10538  }
10539  PopID();
10540 
10542  EndGroup();
10543 
10544  return value_changed;
10545 }
10546 
10547 bool ImGui::InputInt2(const char* label, int v[2], ImGuiInputTextFlags extra_flags)
10548 {
10549  return InputIntN(label, v, 2, extra_flags);
10550 }
10551 
10552 bool ImGui::InputInt3(const char* label, int v[3], ImGuiInputTextFlags extra_flags)
10553 {
10554  return InputIntN(label, v, 3, extra_flags);
10555 }
10556 
10557 bool ImGui::InputInt4(const char* label, int v[4], ImGuiInputTextFlags extra_flags)
10558 {
10559  return InputIntN(label, v, 4, extra_flags);
10560 }
10561 
10562 static float CalcMaxPopupHeightFromItemCount(int items_count)
10563 {
10564  ImGuiContext& g = *GImGui;
10565  if (items_count <= 0)
10566  return FLT_MAX;
10567  return (g.FontSize + g.Style.ItemSpacing.y) * items_count - g.Style.ItemSpacing.y + (g.Style.WindowPadding.y * 2);
10568 }
10569 
10570 bool ImGui::BeginCombo(const char* label, const char* preview_value, ImGuiComboFlags flags)
10571 {
10572  // Always consume the SetNextWindowSizeConstraint() call in our early return paths
10573  ImGuiContext& g = *GImGui;
10574  ImGuiCond backup_next_window_size_constraint = g.NextWindowData.SizeConstraintCond;
10575  g.NextWindowData.SizeConstraintCond = 0;
10576 
10577  ImGuiWindow* window = GetCurrentWindow();
10578  if (window->SkipItems)
10579  return false;
10580 
10581  const ImGuiStyle& style = g.Style;
10582  const ImGuiID id = window->GetID(label);
10583  const float w = CalcItemWidth();
10584 
10585  const ImVec2 label_size = CalcTextSize(label, NULL, true);
10586  const ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(w, label_size.y + style.FramePadding.y*2.0f));
10587  const ImRect total_bb(frame_bb.Min, frame_bb.Max + ImVec2(label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f, 0.0f));
10588  ItemSize(total_bb, style.FramePadding.y);
10589  if (!ItemAdd(total_bb, id, &frame_bb))
10590  return false;
10591 
10592  bool hovered, held;
10593  bool pressed = ButtonBehavior(frame_bb, id, &hovered, &held);
10594  bool popup_open = IsPopupOpen(id);
10595 
10596  const float arrow_size = GetFrameHeight();
10597  const ImRect value_bb(frame_bb.Min, frame_bb.Max - ImVec2(arrow_size, 0.0f));
10598  RenderNavHighlight(frame_bb, id);
10599  RenderFrame(frame_bb.Min, frame_bb.Max, GetColorU32(ImGuiCol_FrameBg), true, style.FrameRounding);
10600  RenderFrame(ImVec2(frame_bb.Max.x-arrow_size, frame_bb.Min.y), frame_bb.Max, GetColorU32(popup_open || hovered ? ImGuiCol_ButtonHovered : ImGuiCol_Button), true, style.FrameRounding); // FIXME-ROUNDING
10601  RenderTriangle(ImVec2(frame_bb.Max.x - arrow_size + style.FramePadding.y, frame_bb.Min.y + style.FramePadding.y), ImGuiDir_Down);
10602  if (preview_value != NULL)
10603  RenderTextClipped(frame_bb.Min + style.FramePadding, value_bb.Max, preview_value, NULL, NULL, ImVec2(0.0f,0.0f));
10604  if (label_size.x > 0)
10605  RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, frame_bb.Min.y + style.FramePadding.y), label);
10606 
10607  if ((pressed || g.NavActivateId == id) && !popup_open)
10608  {
10609  if (window->DC.NavLayerCurrent == 0)
10610  window->NavLastIds[0] = id;
10611  OpenPopupEx(id);
10612  popup_open = true;
10613  }
10614 
10615  if (!popup_open)
10616  return false;
10617 
10618  if (backup_next_window_size_constraint)
10619  {
10620  g.NextWindowData.SizeConstraintCond = backup_next_window_size_constraint;
10621  g.NextWindowData.SizeConstraintRect.Min.x = ImMax(g.NextWindowData.SizeConstraintRect.Min.x, w);
10622  }
10623  else
10624  {
10625  if ((flags & ImGuiComboFlags_HeightMask_) == 0)
10628  int popup_max_height_in_items = -1;
10629  if (flags & ImGuiComboFlags_HeightRegular) popup_max_height_in_items = 8;
10630  else if (flags & ImGuiComboFlags_HeightSmall) popup_max_height_in_items = 4;
10631  else if (flags & ImGuiComboFlags_HeightLarge) popup_max_height_in_items = 20;
10633  }
10634 
10635  char name[16];
10636  ImFormatString(name, IM_ARRAYSIZE(name), "##Combo_%02d", g.CurrentPopupStack.Size); // Recycle windows based on depth
10637 
10638  // Peak into expected window size so we can position it
10639  if (ImGuiWindow* popup_window = FindWindowByName(name))
10640  if (popup_window->WasActive)
10641  {
10642  ImVec2 size_contents = CalcSizeContents(popup_window);
10643  ImVec2 size_expected = CalcSizeAfterConstraint(popup_window, CalcSizeAutoFit(popup_window, size_contents));
10645  popup_window->AutoPosLastDirection = ImGuiDir_Left;
10646  ImVec2 pos = FindBestWindowPosForPopup(frame_bb.GetBL(), size_expected, &popup_window->AutoPosLastDirection, frame_bb, ImGuiPopupPositionPolicy_ComboBox);
10647  SetNextWindowPos(pos);
10648  }
10649 
10651  if (!Begin(name, NULL, window_flags))
10652  {
10653  EndPopup();
10654  IM_ASSERT(0); // This should never happen as we tested for IsPopupOpen() above
10655  return false;
10656  }
10657 
10658  // Horizontally align ourselves with the framed text
10659  if (style.FramePadding.x != style.WindowPadding.x)
10660  Indent(style.FramePadding.x - style.WindowPadding.x);
10661 
10662  return true;
10663 }
10664 
10666 {
10667  const ImGuiStyle& style = GImGui->Style;
10668  if (style.FramePadding.x != style.WindowPadding.x)
10669  Unindent(style.FramePadding.x - style.WindowPadding.x);
10670  EndPopup();
10671 }
10672 
10673 // Old API, prefer using BeginCombo() nowadays if you can.
10674 bool ImGui::Combo(const char* label, int* current_item, bool (*items_getter)(void*, int, const char**), void* data, int items_count, int popup_max_height_in_items)
10675 {
10676  ImGuiContext& g = *GImGui;
10677 
10678  const char* preview_text = NULL;
10679  if (*current_item >= 0 && *current_item < items_count)
10680  items_getter(data, *current_item, &preview_text);
10681 
10682  // The old Combo() API exposed "popup_max_height_in_items", however the new more general BeginCombo() API doesn't, so we emulate it here.
10683  if (popup_max_height_in_items != -1 && !g.NextWindowData.SizeConstraintCond)
10684  {
10685  float popup_max_height = CalcMaxPopupHeightFromItemCount(popup_max_height_in_items);
10686  SetNextWindowSizeConstraints(ImVec2(0,0), ImVec2(FLT_MAX, popup_max_height));
10687  }
10688 
10689  if (!BeginCombo(label, preview_text, 0))
10690  return false;
10691 
10692  // Display items
10693  // FIXME-OPT: Use clipper (but we need to disable it on the appearing frame to make sure our call to SetItemDefaultFocus() is processed)
10694  bool value_changed = false;
10695  for (int i = 0; i < items_count; i++)
10696  {
10697  PushID((void*)(intptr_t)i);
10698  const bool item_selected = (i == *current_item);
10699  const char* item_text;
10700  if (!items_getter(data, i, &item_text))
10701  item_text = "*Unknown item*";
10702  if (Selectable(item_text, item_selected))
10703  {
10704  value_changed = true;
10705  *current_item = i;
10706  }
10707  if (item_selected)
10709  PopID();
10710  }
10711 
10712  EndCombo();
10713  return value_changed;
10714 }
10715 
10716 static bool Items_ArrayGetter(void* data, int idx, const char** out_text)
10717 {
10718  const char* const* items = (const char* const*)data;
10719  if (out_text)
10720  *out_text = items[idx];
10721  return true;
10722 }
10723 
10724 static bool Items_SingleStringGetter(void* data, int idx, const char** out_text)
10725 {
10726  // FIXME-OPT: we could pre-compute the indices to fasten this. But only 1 active combo means the waste is limited.
10727  const char* items_separated_by_zeros = (const char*)data;
10728  int items_count = 0;
10729  const char* p = items_separated_by_zeros;
10730  while (*p)
10731  {
10732  if (idx == items_count)
10733  break;
10734  p += strlen(p) + 1;
10735  items_count++;
10736  }
10737  if (!*p)
10738  return false;
10739  if (out_text)
10740  *out_text = p;
10741  return true;
10742 }
10743 
10744 // Combo box helper allowing to pass an array of strings.
10745 bool ImGui::Combo(const char* label, int* current_item, const char* const items[], int items_count, int height_in_items)
10746 {
10747  const bool value_changed = Combo(label, current_item, Items_ArrayGetter, (void*)items, items_count, height_in_items);
10748  return value_changed;
10749 }
10750 
10751 // Combo box helper allowing to pass all items in a single string.
10752 bool ImGui::Combo(const char* label, int* current_item, const char* items_separated_by_zeros, int height_in_items)
10753 {
10754  int items_count = 0;
10755  const char* p = items_separated_by_zeros; // FIXME-OPT: Avoid computing this, or at least only when combo is open
10756  while (*p)
10757  {
10758  p += strlen(p) + 1;
10759  items_count++;
10760  }
10761  bool value_changed = Combo(label, current_item, Items_SingleStringGetter, (void*)items_separated_by_zeros, items_count, height_in_items);
10762  return value_changed;
10763 }
10764 
10765 // Tip: pass an empty label (e.g. "##dummy") then you can use the space to draw other text or image.
10766 // But you need to make sure the ID is unique, e.g. enclose calls in PushID/PopID.
10767 bool ImGui::Selectable(const char* label, bool selected, ImGuiSelectableFlags flags, const ImVec2& size_arg)
10768 {
10769  ImGuiWindow* window = GetCurrentWindow();
10770  if (window->SkipItems)
10771  return false;
10772 
10773  ImGuiContext& g = *GImGui;
10774  const ImGuiStyle& style = g.Style;
10775 
10776  if ((flags & ImGuiSelectableFlags_SpanAllColumns) && window->DC.ColumnsSet) // FIXME-OPT: Avoid if vertically clipped.
10777  PopClipRect();
10778 
10779  ImGuiID id = window->GetID(label);
10780  ImVec2 label_size = CalcTextSize(label, NULL, true);
10781  ImVec2 size(size_arg.x != 0.0f ? size_arg.x : label_size.x, size_arg.y != 0.0f ? size_arg.y : label_size.y);
10782  ImVec2 pos = window->DC.CursorPos;
10783  pos.y += window->DC.CurrentLineTextBaseOffset;
10784  ImRect bb(pos, pos + size);
10785  ItemSize(bb);
10786 
10787  // Fill horizontal space.
10788  ImVec2 window_padding = window->WindowPadding;
10790  float w_draw = ImMax(label_size.x, window->Pos.x + max_x - window_padding.x - window->DC.CursorPos.x);
10791  ImVec2 size_draw((size_arg.x != 0 && !(flags & ImGuiSelectableFlags_DrawFillAvailWidth)) ? size_arg.x : w_draw, size_arg.y != 0.0f ? size_arg.y : size.y);
10792  ImRect bb_with_spacing(pos, pos + size_draw);
10793  if (size_arg.x == 0.0f || (flags & ImGuiSelectableFlags_DrawFillAvailWidth))
10794  bb_with_spacing.Max.x += window_padding.x;
10795 
10796  // Selectables are tightly packed together, we extend the box to cover spacing between selectable.
10797  float spacing_L = (float)(int)(style.ItemSpacing.x * 0.5f);
10798  float spacing_U = (float)(int)(style.ItemSpacing.y * 0.5f);
10799  float spacing_R = style.ItemSpacing.x - spacing_L;
10800  float spacing_D = style.ItemSpacing.y - spacing_U;
10801  bb_with_spacing.Min.x -= spacing_L;
10802  bb_with_spacing.Min.y -= spacing_U;
10803  bb_with_spacing.Max.x += spacing_R;
10804  bb_with_spacing.Max.y += spacing_D;
10805  if (!ItemAdd(bb_with_spacing, (flags & ImGuiSelectableFlags_Disabled) ? 0 : id))
10806  {
10809  return false;
10810  }
10811 
10812  ImGuiButtonFlags button_flags = 0;
10817  bool hovered, held;
10818  bool pressed = ButtonBehavior(bb_with_spacing, id, &hovered, &held, button_flags);
10820  selected = false;
10821 
10822  // Hovering selectable with mouse updates NavId accordingly so navigation can be resumed with gamepad/keyboard (this doesn't happen on most widgets)
10823  if (pressed || hovered)// && (g.IO.MouseDelta.x != 0.0f || g.IO.MouseDelta.y != 0.0f))
10824  if (!g.NavDisableMouseHover && g.NavWindow == window && g.NavLayer == window->DC.NavLayerActiveMask)
10825  {
10826  g.NavDisableHighlight = true;
10827  SetNavID(id, window->DC.NavLayerCurrent);
10828  }
10829 
10830  // Render
10831  if (hovered || selected)
10832  {
10833  const ImU32 col = GetColorU32((held && hovered) ? ImGuiCol_HeaderActive : hovered ? ImGuiCol_HeaderHovered : ImGuiCol_Header);
10834  RenderFrame(bb_with_spacing.Min, bb_with_spacing.Max, col, false, 0.0f);
10836  }
10837 
10839  {
10841  bb_with_spacing.Max.x -= (GetContentRegionMax().x - max_x);
10842  }
10843 
10845  RenderTextClipped(bb.Min, bb_with_spacing.Max, label, NULL, &label_size, ImVec2(0.0f,0.0f));
10847 
10848  // Automatically close popups
10851  return pressed;
10852 }
10853 
10854 bool ImGui::Selectable(const char* label, bool* p_selected, ImGuiSelectableFlags flags, const ImVec2& size_arg)
10855 {
10856  if (Selectable(label, *p_selected, flags, size_arg))
10857  {
10858  *p_selected = !*p_selected;
10859  return true;
10860  }
10861  return false;
10862 }
10863 
10864 // Helper to calculate the size of a listbox and display a label on the right.
10865 // Tip: To have a list filling the entire window width, PushItemWidth(-1) and pass an empty label "##empty"
10866 bool ImGui::ListBoxHeader(const char* label, const ImVec2& size_arg)
10867 {
10868  ImGuiWindow* window = GetCurrentWindow();
10869  if (window->SkipItems)
10870  return false;
10871 
10872  const ImGuiStyle& style = GetStyle();
10873  const ImGuiID id = GetID(label);
10874  const ImVec2 label_size = CalcTextSize(label, NULL, true);
10875 
10876  // Size default to hold ~7 items. Fractional number of items helps seeing that we can scroll down/up without looking at scrollbar.
10878  ImVec2 frame_size = ImVec2(size.x, ImMax(size.y, label_size.y));
10879  ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + frame_size);
10880  ImRect bb(frame_bb.Min, frame_bb.Max + ImVec2(label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f, 0.0f));
10881  window->DC.LastItemRect = bb; // Forward storage for ListBoxFooter.. dodgy.
10882 
10883  BeginGroup();
10884  if (label_size.x > 0)
10885  RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, frame_bb.Min.y + style.FramePadding.y), label);
10886 
10887  BeginChildFrame(id, frame_bb.GetSize());
10888  return true;
10889 }
10890 
10891 bool ImGui::ListBoxHeader(const char* label, int items_count, int height_in_items)
10892 {
10893  // Size default to hold ~7 items. Fractional number of items helps seeing that we can scroll down/up without looking at scrollbar.
10894  // However we don't add +0.40f if items_count <= height_in_items. It is slightly dodgy, because it means a dynamic list of items will make the widget resize occasionally when it crosses that size.
10895  // I am expecting that someone will come and complain about this behavior in a remote future, then we can advise on a better solution.
10896  if (height_in_items < 0)
10897  height_in_items = ImMin(items_count, 7);
10898  float height_in_items_f = height_in_items < items_count ? (height_in_items + 0.40f) : (height_in_items + 0.00f);
10899 
10900  // We include ItemSpacing.y so that a list sized for the exact number of items doesn't make a scrollbar appears. We could also enforce that by passing a flag to BeginChild().
10901  ImVec2 size;
10902  size.x = 0.0f;
10903  size.y = GetTextLineHeightWithSpacing() * height_in_items_f + GetStyle().ItemSpacing.y;
10904  return ListBoxHeader(label, size);
10905 }
10906 
10908 {
10909  ImGuiWindow* parent_window = GetCurrentWindow()->ParentWindow;
10910  const ImRect bb = parent_window->DC.LastItemRect;
10911  const ImGuiStyle& style = GetStyle();
10912 
10913  EndChildFrame();
10914 
10915  // Redeclare item size so that it includes the label (we have stored the full size in LastItemRect)
10916  // We call SameLine() to restore DC.CurrentLine* data
10917  SameLine();
10918  parent_window->DC.CursorPos = bb.Min;
10919  ItemSize(bb, style.FramePadding.y);
10920  EndGroup();
10921 }
10922 
10923 bool ImGui::ListBox(const char* label, int* current_item, const char* const items[], int items_count, int height_items)
10924 {
10925  const bool value_changed = ListBox(label, current_item, Items_ArrayGetter, (void*)items, items_count, height_items);
10926  return value_changed;
10927 }
10928 
10929 bool ImGui::ListBox(const char* label, int* current_item, bool (*items_getter)(void*, int, const char**), void* data, int items_count, int height_in_items)
10930 {
10931  if (!ListBoxHeader(label, items_count, height_in_items))
10932  return false;
10933 
10934  // Assume all items have even height (= 1 line of text). If you need items of different or variable sizes you can create a custom version of ListBox() in your code without using the clipper.
10935  bool value_changed = false;
10936  ImGuiListClipper clipper(items_count, GetTextLineHeightWithSpacing()); // We know exactly our line height here so we pass it as a minor optimization, but generally you don't need to.
10937  while (clipper.Step())
10938  for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++)
10939  {
10940  const bool item_selected = (i == *current_item);
10941  const char* item_text;
10942  if (!items_getter(data, i, &item_text))
10943  item_text = "*Unknown item*";
10944 
10945  PushID(i);
10946  if (Selectable(item_text, item_selected))
10947  {
10948  *current_item = i;
10949  value_changed = true;
10950  }
10951  if (item_selected)
10953  PopID();
10954  }
10955  ListBoxFooter();
10956  return value_changed;
10957 }
10958 
10959 bool ImGui::MenuItem(const char* label, const char* shortcut, bool selected, bool enabled)
10960 {
10961  ImGuiWindow* window = GetCurrentWindow();
10962  if (window->SkipItems)
10963  return false;
10964 
10965  ImGuiContext& g = *GImGui;
10966  ImGuiStyle& style = g.Style;
10967  ImVec2 pos = window->DC.CursorPos;
10968  ImVec2 label_size = CalcTextSize(label, NULL, true);
10969 
10971  bool pressed;
10972  if (window->DC.LayoutType == ImGuiLayoutType_Horizontal)
10973  {
10974  // Mimic the exact layout spacing of BeginMenu() to allow MenuItem() inside a menu bar, which is a little misleading but may be useful
10975  // Note that in this situation we render neither the shortcut neither the selected tick mark
10976  float w = label_size.x;
10977  window->DC.CursorPos.x += (float)(int)(style.ItemSpacing.x * 0.5f);
10979  pressed = Selectable(label, false, flags, ImVec2(w, 0.0f));
10980  PopStyleVar();
10981  window->DC.CursorPos.x += (float)(int)(style.ItemSpacing.x * (-1.0f + 0.5f)); // -1 spacing to compensate the spacing added when Selectable() did a SameLine(). It would also work to call SameLine() ourselves after the PopStyleVar().
10982  }
10983  else
10984  {
10985  ImVec2 shortcut_size = shortcut ? CalcTextSize(shortcut, NULL) : ImVec2(0.0f, 0.0f);
10986  float w = window->MenuColumns.DeclColumns(label_size.x, shortcut_size.x, (float)(int)(g.FontSize * 1.20f)); // Feedback for next frame
10987  float extra_w = ImMax(0.0f, GetContentRegionAvail().x - w);
10989  if (shortcut_size.x > 0.0f)
10990  {
10992  RenderText(pos + ImVec2(window->MenuColumns.Pos[1] + extra_w, 0.0f), shortcut, NULL, false);
10993  PopStyleColor();
10994  }
10995  if (selected)
10996  RenderCheckMark(pos + ImVec2(window->MenuColumns.Pos[2] + extra_w + g.FontSize * 0.40f, g.FontSize * 0.134f * 0.5f), GetColorU32(enabled ? ImGuiCol_Text : ImGuiCol_TextDisabled), g.FontSize * 0.866f);
10997  }
10998  return pressed;
10999 }
11000 
11001 bool ImGui::MenuItem(const char* label, const char* shortcut, bool* p_selected, bool enabled)
11002 {
11003  if (MenuItem(label, shortcut, p_selected ? *p_selected : false, enabled))
11004  {
11005  if (p_selected)
11006  *p_selected = !*p_selected;
11007  return true;
11008  }
11009  return false;
11010 }
11011 
11013 {
11014  ImGuiContext& g = *GImGui;
11015  SetNextWindowPos(ImVec2(0.0f, 0.0f));
11016  SetNextWindowSize(ImVec2(g.IO.DisplaySize.x, g.FontBaseSize + g.Style.FramePadding.y * 2.0f));
11020  || !BeginMenuBar())
11021  {
11022  End();
11023  PopStyleVar(2);
11024  return false;
11025  }
11026  g.CurrentWindow->DC.MenuBarOffsetX += g.Style.DisplaySafeAreaPadding.x;
11027  return true;
11028 }
11029 
11031 {
11032  EndMenuBar();
11033 
11034  // When the user has left the menu layer (typically: closed menus through activation of an item), we restore focus to the previous window
11035  ImGuiContext& g = *GImGui;
11036  if (g.CurrentWindow == g.NavWindow && g.NavLayer == 0)
11037  FocusFrontMostActiveWindow(g.NavWindow);
11038 
11039  End();
11040  PopStyleVar(2);
11041 }
11042 
11044 {
11045  ImGuiWindow* window = GetCurrentWindow();
11046  if (window->SkipItems)
11047  return false;
11048  if (!(window->Flags & ImGuiWindowFlags_MenuBar))
11049  return false;
11050 
11051  IM_ASSERT(!window->DC.MenuBarAppending);
11052  BeginGroup(); // Save position
11053  PushID("##menubar");
11054 
11055  // We don't clip with regular window clipping rectangle as it is already set to the area below. However we clip with window full rect.
11056  // We remove 1 worth of rounding to Max.x to that text in long menus don't tend to display over the lower-right rounded area, which looks particularly glitchy.
11057  ImRect bar_rect = window->MenuBarRect();
11058  ImRect clip_rect(ImFloor(bar_rect.Min.x + 0.5f), ImFloor(bar_rect.Min.y + window->WindowBorderSize + 0.5f), ImFloor(ImMax(bar_rect.Min.x, bar_rect.Max.x - window->WindowRounding) + 0.5f), ImFloor(bar_rect.Max.y + 0.5f));
11059  clip_rect.ClipWith(window->WindowRectClipped);
11060  PushClipRect(clip_rect.Min, clip_rect.Max, false);
11061 
11062  window->DC.CursorPos = ImVec2(bar_rect.Min.x + window->DC.MenuBarOffsetX, bar_rect.Min.y);// + g.Style.FramePadding.y);
11064  window->DC.NavLayerCurrent++;
11065  window->DC.NavLayerCurrentMask <<= 1;
11066  window->DC.MenuBarAppending = true;
11068  return true;
11069 }
11070 
11072 {
11073  ImGuiWindow* window = GetCurrentWindow();
11074  if (window->SkipItems)
11075  return;
11076  ImGuiContext& g = *GImGui;
11077 
11078  // Nav: When a move request within one of our child menu failed, capture the request to navigate among our siblings.
11079  if (NavMoveRequestButNoResultYet() && (g.NavMoveDir == ImGuiDir_Left || g.NavMoveDir == ImGuiDir_Right) && (g.NavWindow->Flags & ImGuiWindowFlags_ChildMenu))
11080  {
11081  ImGuiWindow* nav_earliest_child = g.NavWindow;
11082  while (nav_earliest_child->ParentWindow && (nav_earliest_child->ParentWindow->Flags & ImGuiWindowFlags_ChildMenu))
11083  nav_earliest_child = nav_earliest_child->ParentWindow;
11084  if (nav_earliest_child->ParentWindow == window && nav_earliest_child->DC.ParentLayoutType == ImGuiLayoutType_Horizontal && g.NavMoveRequestForward == ImGuiNavForward_None)
11085  {
11086  // To do so we claim focus back, restore NavId and then process the movement request for yet another frame.
11087  // This involve a one-frame delay which isn't very problematic in this situation. We could remove it by scoring in advance for multiple window (probably not worth the hassle/cost)
11088  IM_ASSERT(window->DC.NavLayerActiveMaskNext & 0x02); // Sanity check
11089  FocusWindow(window);
11090  SetNavIDAndMoveMouse(window->NavLastIds[1], 1, window->NavRectRel[1]);
11091  g.NavLayer = 1;
11092  g.NavDisableHighlight = true; // Hide highlight for the current frame so we don't see the intermediary selection.
11093  g.NavMoveRequestForward = ImGuiNavForward_ForwardQueued;
11095  }
11096  }
11097 
11099  IM_ASSERT(window->DC.MenuBarAppending);
11100  PopClipRect();
11101  PopID();
11102  window->DC.MenuBarOffsetX = window->DC.CursorPos.x - window->MenuBarRect().Min.x;
11103  window->DC.GroupStack.back().AdvanceCursor = false;
11104  EndGroup();
11106  window->DC.NavLayerCurrent--;
11107  window->DC.NavLayerCurrentMask >>= 1;
11108  window->DC.MenuBarAppending = false;
11109 }
11110 
11111 bool ImGui::BeginMenu(const char* label, bool enabled)
11112 {
11113  ImGuiWindow* window = GetCurrentWindow();
11114  if (window->SkipItems)
11115  return false;
11116 
11117  ImGuiContext& g = *GImGui;
11118  const ImGuiStyle& style = g.Style;
11119  const ImGuiID id = window->GetID(label);
11120 
11121  ImVec2 label_size = CalcTextSize(label, NULL, true);
11122 
11123  bool pressed;
11124  bool menu_is_open = IsPopupOpen(id);
11125  bool menuset_is_open = !(window->Flags & ImGuiWindowFlags_Popup) && (g.OpenPopupStack.Size > g.CurrentPopupStack.Size && g.OpenPopupStack[g.CurrentPopupStack.Size].OpenParentId == window->IDStack.back());
11126  ImGuiWindow* backed_nav_window = g.NavWindow;
11127  if (menuset_is_open)
11128  g.NavWindow = window; // Odd hack to allow hovering across menus of a same menu-set (otherwise we wouldn't be able to hover parent)
11129 
11130  // The reference position stored in popup_pos will be used by Begin() to find a suitable position for the child menu (using FindBestPopupWindowPos).
11131  ImVec2 popup_pos, pos = window->DC.CursorPos;
11132  if (window->DC.LayoutType == ImGuiLayoutType_Horizontal)
11133  {
11134  // Menu inside an horizontal menu bar
11135  // Selectable extend their highlight by half ItemSpacing in each direction.
11136  // For ChildMenu, the popup position will be overwritten by the call to FindBestPopupWindowPos() in Begin()
11137  popup_pos = ImVec2(pos.x - window->WindowPadding.x, pos.y - style.FramePadding.y + window->MenuBarHeight());
11138  window->DC.CursorPos.x += (float)(int)(style.ItemSpacing.x * 0.5f);
11140  float w = label_size.x;
11142  PopStyleVar();
11143  window->DC.CursorPos.x += (float)(int)(style.ItemSpacing.x * (-1.0f + 0.5f)); // -1 spacing to compensate the spacing added when Selectable() did a SameLine(). It would also work to call SameLine() ourselves after the PopStyleVar().
11144  }
11145  else
11146  {
11147  // Menu inside a menu
11148  popup_pos = ImVec2(pos.x, pos.y - style.WindowPadding.y);
11149  float w = window->MenuColumns.DeclColumns(label_size.x, 0.0f, (float)(int)(g.FontSize * 1.20f)); // Feedback to next frame
11150  float extra_w = ImMax(0.0f, GetContentRegionAvail().x - w);
11153  RenderTriangle(pos + ImVec2(window->MenuColumns.Pos[2] + extra_w + g.FontSize * 0.30f, 0.0f), ImGuiDir_Right);
11154  if (!enabled) PopStyleColor();
11155  }
11156 
11157  const bool hovered = enabled && ItemHoverable(window->DC.LastItemRect, id);
11158  if (menuset_is_open)
11159  g.NavWindow = backed_nav_window;
11160 
11161  bool want_open = false, want_close = false;
11162  if (window->DC.LayoutType == ImGuiLayoutType_Vertical) // (window->Flags & (ImGuiWindowFlags_Popup|ImGuiWindowFlags_ChildMenu))
11163  {
11164  // Implement http://bjk5.com/post/44698559168/breaking-down-amazons-mega-dropdown to avoid using timers, so menus feels more reactive.
11165  bool moving_within_opened_triangle = false;
11166  if (g.HoveredWindow == window && g.OpenPopupStack.Size > g.CurrentPopupStack.Size && g.OpenPopupStack[g.CurrentPopupStack.Size].ParentWindow == window && !(window->Flags & ImGuiWindowFlags_MenuBar))
11167  {
11168  if (ImGuiWindow* next_window = g.OpenPopupStack[g.CurrentPopupStack.Size].Window)
11169  {
11170  ImRect next_window_rect = next_window->Rect();
11171  ImVec2 ta = g.IO.MousePos - g.IO.MouseDelta;
11172  ImVec2 tb = (window->Pos.x < next_window->Pos.x) ? next_window_rect.GetTL() : next_window_rect.GetTR();
11173  ImVec2 tc = (window->Pos.x < next_window->Pos.x) ? next_window_rect.GetBL() : next_window_rect.GetBR();
11174  float extra = ImClamp(fabsf(ta.x - tb.x) * 0.30f, 5.0f, 30.0f); // add a bit of extra slack.
11175  ta.x += (window->Pos.x < next_window->Pos.x) ? -0.5f : +0.5f; // to avoid numerical issues
11176  tb.y = ta.y + ImMax((tb.y - extra) - ta.y, -100.0f); // triangle is maximum 200 high to limit the slope and the bias toward large sub-menus // FIXME: Multiply by fb_scale?
11177  tc.y = ta.y + ImMin((tc.y + extra) - ta.y, +100.0f);
11178  moving_within_opened_triangle = ImTriangleContainsPoint(ta, tb, tc, g.IO.MousePos);
11179  //window->DrawList->PushClipRectFullScreen(); window->DrawList->AddTriangleFilled(ta, tb, tc, moving_within_opened_triangle ? IM_COL32(0,128,0,128) : IM_COL32(128,0,0,128)); window->DrawList->PopClipRect(); // Debug
11180  }
11181  }
11182 
11183  want_close = (menu_is_open && !hovered && g.HoveredWindow == window && g.HoveredIdPreviousFrame != 0 && g.HoveredIdPreviousFrame != id && !moving_within_opened_triangle);
11184  want_open = (!menu_is_open && hovered && !moving_within_opened_triangle) || (!menu_is_open && hovered && pressed);
11185 
11186  if (g.NavActivateId == id)
11187  {
11188  want_close = menu_is_open;
11189  want_open = !menu_is_open;
11190  }
11191  if (g.NavId == id && g.NavMoveRequest && g.NavMoveDir == ImGuiDir_Right) // Nav-Right to open
11192  {
11193  want_open = true;
11195  }
11196  }
11197  else
11198  {
11199  // Menu bar
11200  if (menu_is_open && pressed && menuset_is_open) // Click an open menu again to close it
11201  {
11202  want_close = true;
11203  want_open = menu_is_open = false;
11204  }
11205  else if (pressed || (hovered && menuset_is_open && !menu_is_open)) // First click to open, then hover to open others
11206  {
11207  want_open = true;
11208  }
11209  else if (g.NavId == id && g.NavMoveRequest && g.NavMoveDir == ImGuiDir_Down) // Nav-Down to open
11210  {
11211  want_open = true;
11213  }
11214  }
11215 
11216  if (!enabled) // explicitly close if an open menu becomes disabled, facilitate users code a lot in pattern such as 'if (BeginMenu("options", has_object)) { ..use object.. }'
11217  want_close = true;
11218  if (want_close && IsPopupOpen(id))
11219  ClosePopupToLevel(g.CurrentPopupStack.Size);
11220 
11221  if (!menu_is_open && want_open && g.OpenPopupStack.Size > g.CurrentPopupStack.Size)
11222  {
11223  // Don't recycle same menu level in the same frame, first close the other menu and yield for a frame.
11224  OpenPopup(label);
11225  return false;
11226  }
11227 
11228  menu_is_open |= want_open;
11229  if (want_open)
11230  OpenPopup(label);
11231 
11232  if (menu_is_open)
11233  {
11234  SetNextWindowPos(popup_pos, ImGuiCond_Always);
11236  menu_is_open = BeginPopupEx(id, flags); // menu_is_open can be 'false' when the popup is completely clipped (e.g. zero size display)
11237  }
11238 
11239  return menu_is_open;
11240 }
11241 
11243 {
11244  // Nav: When a left move request _within our child menu_ failed, close the menu.
11245  // A menu doesn't close itself because EndMenuBar() wants the catch the last Left<>Right inputs.
11246  // However it means that with the current code, a BeginMenu() from outside another menu or a menu-bar won't be closable with the Left direction.
11247  ImGuiContext& g = *GImGui;
11248  ImGuiWindow* window = g.CurrentWindow;
11249  if (g.NavWindow && g.NavWindow->ParentWindow == window && g.NavMoveDir == ImGuiDir_Left && NavMoveRequestButNoResultYet() && window->DC.LayoutType == ImGuiLayoutType_Vertical)
11250  {
11251  ClosePopupToLevel(g.OpenPopupStack.Size - 1);
11253  }
11254 
11255  EndPopup();
11256 }
11257 
11258 // Note: only access 3 floats if ImGuiColorEditFlags_NoAlpha flag is set.
11259 void ImGui::ColorTooltip(const char* text, const float* col, ImGuiColorEditFlags flags)
11260 {
11261  ImGuiContext& g = *GImGui;
11262 
11263  int cr = IM_F32_TO_INT8_SAT(col[0]), cg = IM_F32_TO_INT8_SAT(col[1]), cb = IM_F32_TO_INT8_SAT(col[2]), ca = (flags & ImGuiColorEditFlags_NoAlpha) ? 255 : IM_F32_TO_INT8_SAT(col[3]);
11264  BeginTooltipEx(0, true);
11265 
11266  const char* text_end = text ? FindRenderedTextEnd(text, NULL) : text;
11267  if (text_end > text)
11268  {
11269  TextUnformatted(text, text_end);
11270  Separator();
11271  }
11272 
11273  ImVec2 sz(g.FontSize * 3 + g.Style.FramePadding.y * 2, g.FontSize * 3 + g.Style.FramePadding.y * 2);
11275  SameLine();
11277  Text("#%02X%02X%02X\nR: %d, G: %d, B: %d\n(%.3f, %.3f, %.3f)", cr, cg, cb, cr, cg, cb, col[0], col[1], col[2]);
11278  else
11279  Text("#%02X%02X%02X%02X\nR:%d, G:%d, B:%d, A:%d\n(%.3f, %.3f, %.3f, %.3f)", cr, cg, cb, ca, cr, cg, cb, ca, col[0], col[1], col[2], col[3]);
11280  EndTooltip();
11281 }
11282 
11283 static inline ImU32 ImAlphaBlendColor(ImU32 col_a, ImU32 col_b)
11284 {
11285  float t = ((col_b >> IM_COL32_A_SHIFT) & 0xFF) / 255.f;
11286  int r = ImLerp((int)(col_a >> IM_COL32_R_SHIFT) & 0xFF, (int)(col_b >> IM_COL32_R_SHIFT) & 0xFF, t);
11287  int g = ImLerp((int)(col_a >> IM_COL32_G_SHIFT) & 0xFF, (int)(col_b >> IM_COL32_G_SHIFT) & 0xFF, t);
11288  int b = ImLerp((int)(col_a >> IM_COL32_B_SHIFT) & 0xFF, (int)(col_b >> IM_COL32_B_SHIFT) & 0xFF, t);
11289  return IM_COL32(r, g, b, 0xFF);
11290 }
11291 
11292 // NB: This is rather brittle and will show artifact when rounding this enabled if rounded corners overlap multiple cells. Caller currently responsible for avoiding that.
11293 // I spent a non reasonable amount of time trying to getting this right for ColorButton with rounding+anti-aliasing+ImGuiColorEditFlags_HalfAlphaPreview flag + various grid sizes and offsets, and eventually gave up... probably more reasonable to disable rounding alltogether.
11294 void ImGui::RenderColorRectWithAlphaCheckerboard(ImVec2 p_min, ImVec2 p_max, ImU32 col, float grid_step, ImVec2 grid_off, float rounding, int rounding_corners_flags)
11295 {
11296  ImGuiWindow* window = GetCurrentWindow();
11297  if (((col & IM_COL32_A_MASK) >> IM_COL32_A_SHIFT) < 0xFF)
11298  {
11299  ImU32 col_bg1 = GetColorU32(ImAlphaBlendColor(IM_COL32(204,204,204,255), col));
11300  ImU32 col_bg2 = GetColorU32(ImAlphaBlendColor(IM_COL32(128,128,128,255), col));
11301  window->DrawList->AddRectFilled(p_min, p_max, col_bg1, rounding, rounding_corners_flags);
11302 
11303  int yi = 0;
11304  for (float y = p_min.y + grid_off.y; y < p_max.y; y += grid_step, yi++)
11305  {
11306  float y1 = ImClamp(y, p_min.y, p_max.y), y2 = ImMin(y + grid_step, p_max.y);
11307  if (y2 <= y1)
11308  continue;
11309  for (float x = p_min.x + grid_off.x + (yi & 1) * grid_step; x < p_max.x; x += grid_step * 2.0f)
11310  {
11311  float x1 = ImClamp(x, p_min.x, p_max.x), x2 = ImMin(x + grid_step, p_max.x);
11312  if (x2 <= x1)
11313  continue;
11314  int rounding_corners_flags_cell = 0;
11315  if (y1 <= p_min.y) { if (x1 <= p_min.x) rounding_corners_flags_cell |= ImDrawCornerFlags_TopLeft; if (x2 >= p_max.x) rounding_corners_flags_cell |= ImDrawCornerFlags_TopRight; }
11316  if (y2 >= p_max.y) { if (x1 <= p_min.x) rounding_corners_flags_cell |= ImDrawCornerFlags_BotLeft; if (x2 >= p_max.x) rounding_corners_flags_cell |= ImDrawCornerFlags_BotRight; }
11317  rounding_corners_flags_cell &= rounding_corners_flags;
11318  window->DrawList->AddRectFilled(ImVec2(x1,y1), ImVec2(x2,y2), col_bg2, rounding_corners_flags_cell ? rounding : 0.0f, rounding_corners_flags_cell);
11319  }
11320  }
11321  }
11322  else
11323  {
11324  window->DrawList->AddRectFilled(p_min, p_max, col, rounding, rounding_corners_flags);
11325  }
11326 }
11327 
11329 {
11330  ImGuiContext& g = *GImGui;
11337  IM_ASSERT(ImIsPowerOfTwo((int)(flags & ImGuiColorEditFlags__InputsMask))); // Check only 1 option is selected
11338  IM_ASSERT(ImIsPowerOfTwo((int)(flags & ImGuiColorEditFlags__DataTypeMask))); // Check only 1 option is selected
11339  IM_ASSERT(ImIsPowerOfTwo((int)(flags & ImGuiColorEditFlags__PickerMask))); // Check only 1 option is selected
11340  g.ColorEditOptions = flags;
11341 }
11342 
11343 // A little colored square. Return true when clicked.
11344 // FIXME: May want to display/ignore the alpha component in the color display? Yet show it in the tooltip.
11345 // 'desc_id' is not called 'label' because we don't display it next to the button, but only in the tooltip.
11346 bool ImGui::ColorButton(const char* desc_id, const ImVec4& col, ImGuiColorEditFlags flags, ImVec2 size)
11347 {
11348  ImGuiWindow* window = GetCurrentWindow();
11349  if (window->SkipItems)
11350  return false;
11351 
11352  ImGuiContext& g = *GImGui;
11353  const ImGuiID id = window->GetID(desc_id);
11354  float default_size = GetFrameHeight();
11355  if (size.x == 0.0f)
11356  size.x = default_size;
11357  if (size.y == 0.0f)
11358  size.y = default_size;
11359  const ImRect bb(window->DC.CursorPos, window->DC.CursorPos + size);
11360  ItemSize(bb, (size.y >= default_size) ? g.Style.FramePadding.y : 0.0f);
11361  if (!ItemAdd(bb, id))
11362  return false;
11363 
11364  bool hovered, held;
11365  bool pressed = ButtonBehavior(bb, id, &hovered, &held);
11366 
11369 
11370  ImVec4 col_without_alpha(col.x, col.y, col.z, 1.0f);
11371  float grid_step = ImMin(size.x, size.y) / 2.99f;
11372  float rounding = ImMin(g.Style.FrameRounding, grid_step * 0.5f);
11373  ImRect bb_inner = bb;
11374  float off = -0.75f; // The border (using Col_FrameBg) tends to look off when color is near-opaque and rounding is enabled. This offset seemed like a good middle ground to reduce those artifacts.
11375  bb_inner.Expand(off);
11376  if ((flags & ImGuiColorEditFlags_AlphaPreviewHalf) && col.w < 1.0f)
11377  {
11378  float mid_x = (float)(int)((bb_inner.Min.x + bb_inner.Max.x) * 0.5f + 0.5f);
11379  RenderColorRectWithAlphaCheckerboard(ImVec2(bb_inner.Min.x + grid_step, bb_inner.Min.y), bb_inner.Max, GetColorU32(col), grid_step, ImVec2(-grid_step + off, off), rounding, ImDrawCornerFlags_TopRight| ImDrawCornerFlags_BotRight);
11380  window->DrawList->AddRectFilled(bb_inner.Min, ImVec2(mid_x, bb_inner.Max.y), GetColorU32(col_without_alpha), rounding, ImDrawCornerFlags_TopLeft|ImDrawCornerFlags_BotLeft);
11381  }
11382  else
11383  {
11384  // Because GetColorU32() multiplies by the global style Alpha and we don't want to display a checkerboard if the source code had no alpha
11385  ImVec4 col_source = (flags & ImGuiColorEditFlags_AlphaPreview) ? col : col_without_alpha;
11386  if (col_source.w < 1.0f)
11387  RenderColorRectWithAlphaCheckerboard(bb_inner.Min, bb_inner.Max, GetColorU32(col_source), grid_step, ImVec2(off, off), rounding);
11388  else
11389  window->DrawList->AddRectFilled(bb_inner.Min, bb_inner.Max, GetColorU32(col_source), rounding, ImDrawCornerFlags_All);
11390  }
11391  RenderNavHighlight(bb, id);
11392  if (g.Style.FrameBorderSize > 0.0f)
11393  RenderFrameBorder(bb.Min, bb.Max, rounding);
11394  else
11395  window->DrawList->AddRect(bb.Min, bb.Max, GetColorU32(ImGuiCol_FrameBg), rounding); // Color button are often in need of some sort of border
11396 
11397  // Drag and Drop Source
11398  if (g.ActiveId == id && BeginDragDropSource()) // NB: The ActiveId test is merely an optional micro-optimization
11399  {
11402  else
11404  ColorButton(desc_id, col, flags);
11405  SameLine();
11406  TextUnformatted("Color");
11408  hovered = false;
11409  }
11410 
11411  // Tooltip
11412  if (!(flags & ImGuiColorEditFlags_NoTooltip) && hovered)
11414 
11415  return pressed;
11416 }
11417 
11418 bool ImGui::ColorEdit3(const char* label, float col[3], ImGuiColorEditFlags flags)
11419 {
11421 }
11422 
11424 {
11425  bool allow_opt_inputs = !(flags & ImGuiColorEditFlags__InputsMask);
11426  bool allow_opt_datatype = !(flags & ImGuiColorEditFlags__DataTypeMask);
11427  if ((!allow_opt_inputs && !allow_opt_datatype) || !BeginPopup("context"))
11428  return;
11429  ImGuiContext& g = *GImGui;
11431  if (allow_opt_inputs)
11432  {
11433  if (RadioButton("RGB", (opts & ImGuiColorEditFlags_RGB) ? 1 : 0)) opts = (opts & ~ImGuiColorEditFlags__InputsMask) | ImGuiColorEditFlags_RGB;
11434  if (RadioButton("HSV", (opts & ImGuiColorEditFlags_HSV) ? 1 : 0)) opts = (opts & ~ImGuiColorEditFlags__InputsMask) | ImGuiColorEditFlags_HSV;
11435  if (RadioButton("HEX", (opts & ImGuiColorEditFlags_HEX) ? 1 : 0)) opts = (opts & ~ImGuiColorEditFlags__InputsMask) | ImGuiColorEditFlags_HEX;
11436  }
11437  if (allow_opt_datatype)
11438  {
11439  if (allow_opt_inputs) Separator();
11440  if (RadioButton("0..255", (opts & ImGuiColorEditFlags_Uint8) ? 1 : 0)) opts = (opts & ~ImGuiColorEditFlags__DataTypeMask) | ImGuiColorEditFlags_Uint8;
11441  if (RadioButton("0.00..1.00", (opts & ImGuiColorEditFlags_Float) ? 1 : 0)) opts = (opts & ~ImGuiColorEditFlags__DataTypeMask) | ImGuiColorEditFlags_Float;
11442  }
11443 
11444  if (allow_opt_inputs || allow_opt_datatype)
11445  Separator();
11446  if (Button("Copy as..", ImVec2(-1,0)))
11447  OpenPopup("Copy");
11448  if (BeginPopup("Copy"))
11449  {
11450  int cr = IM_F32_TO_INT8_SAT(col[0]), cg = IM_F32_TO_INT8_SAT(col[1]), cb = IM_F32_TO_INT8_SAT(col[2]), ca = (flags & ImGuiColorEditFlags_NoAlpha) ? 255 : IM_F32_TO_INT8_SAT(col[3]);
11451  char buf[64];
11452  ImFormatString(buf, IM_ARRAYSIZE(buf), "(%.3ff, %.3ff, %.3ff, %.3ff)", col[0], col[1], col[2], (flags & ImGuiColorEditFlags_NoAlpha) ? 1.0f : col[3]);
11453  if (Selectable(buf))
11455  ImFormatString(buf, IM_ARRAYSIZE(buf), "(%d,%d,%d,%d)", cr, cg, cb, ca);
11456  if (Selectable(buf))
11459  ImFormatString(buf, IM_ARRAYSIZE(buf), "0x%02X%02X%02X", cr, cg, cb);
11460  else
11461  ImFormatString(buf, IM_ARRAYSIZE(buf), "0x%02X%02X%02X%02X", cr, cg, cb, ca);
11462  if (Selectable(buf))
11464  EndPopup();
11465  }
11466 
11467  g.ColorEditOptions = opts;
11468  EndPopup();
11469 }
11470 
11471 static void ColorPickerOptionsPopup(ImGuiColorEditFlags flags, const float* ref_col)
11472 {
11473  bool allow_opt_picker = !(flags & ImGuiColorEditFlags__PickerMask);
11474  bool allow_opt_alpha_bar = !(flags & ImGuiColorEditFlags_NoAlpha) && !(flags & ImGuiColorEditFlags_AlphaBar);
11475  if ((!allow_opt_picker && !allow_opt_alpha_bar) || !ImGui::BeginPopup("context"))
11476  return;
11477  ImGuiContext& g = *GImGui;
11478  if (allow_opt_picker)
11479  {
11480  ImVec2 picker_size(g.FontSize * 8, ImMax(g.FontSize * 8 - (ImGui::GetFrameHeight() + g.Style.ItemInnerSpacing.x), 1.0f)); // FIXME: Picker size copied from main picker function
11481  ImGui::PushItemWidth(picker_size.x);
11482  for (int picker_type = 0; picker_type < 2; picker_type++)
11483  {
11484  // Draw small/thumbnail version of each picker type (over an invisible button for selection)
11485  if (picker_type > 0) ImGui::Separator();
11486  ImGui::PushID(picker_type);
11488  if (picker_type == 0) picker_flags |= ImGuiColorEditFlags_PickerHueBar;
11489  if (picker_type == 1) picker_flags |= ImGuiColorEditFlags_PickerHueWheel;
11490  ImVec2 backup_pos = ImGui::GetCursorScreenPos();
11491  if (ImGui::Selectable("##selectable", false, 0, picker_size)) // By default, Selectable() is closing popup
11492  g.ColorEditOptions = (g.ColorEditOptions & ~ImGuiColorEditFlags__PickerMask) | (picker_flags & ImGuiColorEditFlags__PickerMask);
11493  ImGui::SetCursorScreenPos(backup_pos);
11494  ImVec4 dummy_ref_col;
11495  memcpy(&dummy_ref_col.x, ref_col, sizeof(float) * (picker_flags & ImGuiColorEditFlags_NoAlpha ? 3 : 4));
11496  ImGui::ColorPicker4("##dummypicker", &dummy_ref_col.x, picker_flags);
11497  ImGui::PopID();
11498  }
11500  }
11501  if (allow_opt_alpha_bar)
11502  {
11503  if (allow_opt_picker) ImGui::Separator();
11504  ImGui::CheckboxFlags("Alpha Bar", (unsigned int*)&g.ColorEditOptions, ImGuiColorEditFlags_AlphaBar);
11505  }
11506  ImGui::EndPopup();
11507 }
11508 
11509 // Edit colors components (each component in 0.0f..1.0f range).
11510 // See enum ImGuiColorEditFlags_ for available options. e.g. Only access 3 floats if ImGuiColorEditFlags_NoAlpha flag is set.
11511 // With typical options: Left-click on colored square to open color picker. Right-click to open option menu. CTRL-Click over input fields to edit them and TAB to go to next item.
11512 bool ImGui::ColorEdit4(const char* label, float col[4], ImGuiColorEditFlags flags)
11513 {
11514  ImGuiWindow* window = GetCurrentWindow();
11515  if (window->SkipItems)
11516  return false;
11517 
11518  ImGuiContext& g = *GImGui;
11519  const ImGuiStyle& style = g.Style;
11520  const float square_sz = GetFrameHeight();
11521  const float w_extra = (flags & ImGuiColorEditFlags_NoSmallPreview) ? 0.0f : (square_sz + style.ItemInnerSpacing.x);
11522  const float w_items_all = CalcItemWidth() - w_extra;
11523  const char* label_display_end = FindRenderedTextEnd(label);
11524 
11525  const bool alpha = (flags & ImGuiColorEditFlags_NoAlpha) == 0;
11526  const bool hdr = (flags & ImGuiColorEditFlags_HDR) != 0;
11527  const int components = alpha ? 4 : 3;
11528  const ImGuiColorEditFlags flags_untouched = flags;
11529 
11530  BeginGroup();
11531  PushID(label);
11532 
11533  // If we're not showing any slider there's no point in doing any HSV conversions
11536 
11537  // Context menu: display and modify options (before defaults are applied)
11540 
11541  // Read stored options
11543  flags |= (g.ColorEditOptions & ImGuiColorEditFlags__InputsMask);
11545  flags |= (g.ColorEditOptions & ImGuiColorEditFlags__DataTypeMask);
11547  flags |= (g.ColorEditOptions & ImGuiColorEditFlags__PickerMask);
11549 
11550  // Convert to the formats we need
11551  float f[4] = { col[0], col[1], col[2], alpha ? col[3] : 1.0f };
11553  ColorConvertRGBtoHSV(f[0], f[1], f[2], f[0], f[1], f[2]);
11555 
11556  bool value_changed = false;
11557  bool value_changed_as_float = false;
11558 
11560  {
11561  // RGB/HSV 0..255 Sliders
11562  const float w_item_one = ImMax(1.0f, (float)(int)((w_items_all - (style.ItemInnerSpacing.x) * (components-1)) / (float)components));
11563  const float w_item_last = ImMax(1.0f, (float)(int)(w_items_all - (w_item_one + style.ItemInnerSpacing.x) * (components-1)));
11564 
11565  const bool hide_prefix = (w_item_one <= CalcTextSize((flags & ImGuiColorEditFlags_Float) ? "M:0.000" : "M:000").x);
11566  const char* ids[4] = { "##X", "##Y", "##Z", "##W" };
11567  const char* fmt_table_int[3][4] =
11568  {
11569  { "%3.0f", "%3.0f", "%3.0f", "%3.0f" }, // Short display
11570  { "R:%3.0f", "G:%3.0f", "B:%3.0f", "A:%3.0f" }, // Long display for RGBA
11571  { "H:%3.0f", "S:%3.0f", "V:%3.0f", "A:%3.0f" } // Long display for HSVA
11572  };
11573  const char* fmt_table_float[3][4] =
11574  {
11575  { "%0.3f", "%0.3f", "%0.3f", "%0.3f" }, // Short display
11576  { "R:%0.3f", "G:%0.3f", "B:%0.3f", "A:%0.3f" }, // Long display for RGBA
11577  { "H:%0.3f", "S:%0.3f", "V:%0.3f", "A:%0.3f" } // Long display for HSVA
11578  };
11579  const int fmt_idx = hide_prefix ? 0 : (flags & ImGuiColorEditFlags_HSV) ? 2 : 1;
11580 
11581  PushItemWidth(w_item_one);
11582  for (int n = 0; n < components; n++)
11583  {
11584  if (n > 0)
11585  SameLine(0, style.ItemInnerSpacing.x);
11586  if (n + 1 == components)
11587  PushItemWidth(w_item_last);
11589  value_changed = value_changed_as_float = value_changed | DragFloat(ids[n], &f[n], 1.0f/255.0f, 0.0f, hdr ? 0.0f : 1.0f, fmt_table_float[fmt_idx][n]);
11590  else
11591  value_changed |= DragInt(ids[n], &i[n], 1.0f, 0, hdr ? 0 : 255, fmt_table_int[fmt_idx][n]);
11593  OpenPopupOnItemClick("context");
11594  }
11595  PopItemWidth();
11596  PopItemWidth();
11597  }
11598  else if ((flags & ImGuiColorEditFlags_HEX) != 0 && (flags & ImGuiColorEditFlags_NoInputs) == 0)
11599  {
11600  // RGB Hexadecimal Input
11601  char buf[64];
11602  if (alpha)
11603  ImFormatString(buf, IM_ARRAYSIZE(buf), "#%02X%02X%02X%02X", ImClamp(i[0],0,255), ImClamp(i[1],0,255), ImClamp(i[2],0,255), ImClamp(i[3],0,255));
11604  else
11605  ImFormatString(buf, IM_ARRAYSIZE(buf), "#%02X%02X%02X", ImClamp(i[0],0,255), ImClamp(i[1],0,255), ImClamp(i[2],0,255));
11606  PushItemWidth(w_items_all);
11608  {
11609  value_changed = true;
11610  char* p = buf;
11611  while (*p == '#' || ImCharIsSpace(*p))
11612  p++;
11613  i[0] = i[1] = i[2] = i[3] = 0;
11614  if (alpha)
11615  sscanf(p, "%02X%02X%02X%02X", (unsigned int*)&i[0], (unsigned int*)&i[1], (unsigned int*)&i[2], (unsigned int*)&i[3]); // Treat at unsigned (%X is unsigned)
11616  else
11617  sscanf(p, "%02X%02X%02X", (unsigned int*)&i[0], (unsigned int*)&i[1], (unsigned int*)&i[2]);
11618  }
11620  OpenPopupOnItemClick("context");
11621  PopItemWidth();
11622  }
11623 
11624  ImGuiWindow* picker_active_window = NULL;
11626  {
11628  SameLine(0, style.ItemInnerSpacing.x);
11629 
11630  const ImVec4 col_v4(col[0], col[1], col[2], alpha ? col[3] : 1.0f);
11631  if (ColorButton("##ColorButton", col_v4, flags))
11632  {
11634  {
11635  // Store current color and open a picker
11636  g.ColorPickerRef = col_v4;
11637  OpenPopup("picker");
11638  SetNextWindowPos(window->DC.LastItemRect.GetBL() + ImVec2(-1,style.ItemSpacing.y));
11639  }
11640  }
11642  OpenPopupOnItemClick("context");
11643 
11644  if (BeginPopup("picker"))
11645  {
11646  picker_active_window = g.CurrentWindow;
11647  if (label != label_display_end)
11648  {
11649  TextUnformatted(label, label_display_end);
11650  Separator();
11651  }
11653  ImGuiColorEditFlags picker_flags = (flags_untouched & picker_flags_to_forward) | ImGuiColorEditFlags__InputsMask | ImGuiColorEditFlags_NoLabel | ImGuiColorEditFlags_AlphaPreviewHalf;
11654  PushItemWidth(square_sz * 12.0f); // Use 256 + bar sizes?
11655  value_changed |= ColorPicker4("##picker", col, picker_flags, &g.ColorPickerRef.x);
11656  PopItemWidth();
11657  EndPopup();
11658  }
11659  }
11660 
11661  if (label != label_display_end && !(flags & ImGuiColorEditFlags_NoLabel))
11662  {
11663  SameLine(0, style.ItemInnerSpacing.x);
11664  TextUnformatted(label, label_display_end);
11665  }
11666 
11667  // Convert back
11668  if (picker_active_window == NULL)
11669  {
11670  if (!value_changed_as_float)
11671  for (int n = 0; n < 4; n++)
11672  f[n] = i[n] / 255.0f;
11674  ColorConvertHSVtoRGB(f[0], f[1], f[2], f[0], f[1], f[2]);
11675  if (value_changed)
11676  {
11677  col[0] = f[0];
11678  col[1] = f[1];
11679  col[2] = f[2];
11680  if (alpha)
11681  col[3] = f[3];
11682  }
11683  }
11684 
11685  PopID();
11686  EndGroup();
11687 
11688  // Drag and Drop Target
11689  if ((window->DC.LastItemStatusFlags & ImGuiItemStatusFlags_HoveredRect) && BeginDragDropTarget()) // NB: The flag test is merely an optional micro-optimization, BeginDragDropTarget() does the same test.
11690  {
11692  {
11693  memcpy((float*)col, payload->Data, sizeof(float) * 3);
11694  value_changed = true;
11695  }
11697  {
11698  memcpy((float*)col, payload->Data, sizeof(float) * components);
11699  value_changed = true;
11700  }
11702  }
11703 
11704  // When picker is being actively used, use its active id so IsItemActive() will function on ColorEdit4().
11705  if (picker_active_window && g.ActiveId != 0 && g.ActiveIdWindow == picker_active_window)
11706  window->DC.LastItemId = g.ActiveId;
11707 
11708  return value_changed;
11709 }
11710 
11711 bool ImGui::ColorPicker3(const char* label, float col[3], ImGuiColorEditFlags flags)
11712 {
11713  float col4[4] = { col[0], col[1], col[2], 1.0f };
11715  return false;
11716  col[0] = col4[0]; col[1] = col4[1]; col[2] = col4[2];
11717  return true;
11718 }
11719 
11720 // 'pos' is position of the arrow tip. half_sz.x is length from base to tip. half_sz.y is length on each side.
11721 static void RenderArrow(ImDrawList* draw_list, ImVec2 pos, ImVec2 half_sz, ImGuiDir direction, ImU32 col)
11722 {
11723  switch (direction)
11724  {
11725  case ImGuiDir_Left: draw_list->AddTriangleFilled(ImVec2(pos.x + half_sz.x, pos.y - half_sz.y), ImVec2(pos.x + half_sz.x, pos.y + half_sz.y), pos, col); return;
11726  case ImGuiDir_Right: draw_list->AddTriangleFilled(ImVec2(pos.x - half_sz.x, pos.y + half_sz.y), ImVec2(pos.x - half_sz.x, pos.y - half_sz.y), pos, col); return;
11727  case ImGuiDir_Up: draw_list->AddTriangleFilled(ImVec2(pos.x + half_sz.x, pos.y + half_sz.y), ImVec2(pos.x - half_sz.x, pos.y + half_sz.y), pos, col); return;
11728  case ImGuiDir_Down: draw_list->AddTriangleFilled(ImVec2(pos.x - half_sz.x, pos.y - half_sz.y), ImVec2(pos.x + half_sz.x, pos.y - half_sz.y), pos, col); return;
11729  case ImGuiDir_None: case ImGuiDir_Count_: break; // Fix warnings
11730  }
11731 }
11732 
11733 static void RenderArrowsForVerticalBar(ImDrawList* draw_list, ImVec2 pos, ImVec2 half_sz, float bar_w)
11734 {
11735  RenderArrow(draw_list, ImVec2(pos.x + half_sz.x + 1, pos.y), ImVec2(half_sz.x + 2, half_sz.y + 1), ImGuiDir_Right, IM_COL32_BLACK);
11736  RenderArrow(draw_list, ImVec2(pos.x + half_sz.x, pos.y), half_sz, ImGuiDir_Right, IM_COL32_WHITE);
11737  RenderArrow(draw_list, ImVec2(pos.x + bar_w - half_sz.x - 1, pos.y), ImVec2(half_sz.x + 2, half_sz.y + 1), ImGuiDir_Left, IM_COL32_BLACK);
11738  RenderArrow(draw_list, ImVec2(pos.x + bar_w - half_sz.x, pos.y), half_sz, ImGuiDir_Left, IM_COL32_WHITE);
11739 }
11740 
11741 // ColorPicker
11742 // Note: only access 3 floats if ImGuiColorEditFlags_NoAlpha flag is set.
11743 // FIXME: we adjust the big color square height based on item width, which may cause a flickering feedback loop (if automatic height makes a vertical scrollbar appears, affecting automatic width..)
11744 bool ImGui::ColorPicker4(const char* label, float col[4], ImGuiColorEditFlags flags, const float* ref_col)
11745 {
11746  ImGuiContext& g = *GImGui;
11747  ImGuiWindow* window = GetCurrentWindow();
11748  ImDrawList* draw_list = window->DrawList;
11749 
11750  ImGuiStyle& style = g.Style;
11751  ImGuiIO& io = g.IO;
11752 
11753  PushID(label);
11754  BeginGroup();
11755 
11758 
11759  // Context menu: display and store options.
11762 
11763  // Read stored options
11766  IM_ASSERT(ImIsPowerOfTwo((int)(flags & ImGuiColorEditFlags__PickerMask))); // Check that only 1 is selected
11768  flags |= (g.ColorEditOptions & ImGuiColorEditFlags_AlphaBar);
11769 
11770  // Setup
11771  int components = (flags & ImGuiColorEditFlags_NoAlpha) ? 3 : 4;
11773  ImVec2 picker_pos = window->DC.CursorPos;
11774  float square_sz = GetFrameHeight();
11775  float bars_width = square_sz; // Arbitrary smallish width of Hue/Alpha picking bars
11776  float sv_picker_size = ImMax(bars_width * 1, CalcItemWidth() - (alpha_bar ? 2 : 1) * (bars_width + style.ItemInnerSpacing.x)); // Saturation/Value picking box
11777  float bar0_pos_x = picker_pos.x + sv_picker_size + style.ItemInnerSpacing.x;
11778  float bar1_pos_x = bar0_pos_x + bars_width + style.ItemInnerSpacing.x;
11779  float bars_triangles_half_sz = (float)(int)(bars_width * 0.20f);
11780 
11781  float backup_initial_col[4];
11782  memcpy(backup_initial_col, col, components * sizeof(float));
11783 
11784  float wheel_thickness = sv_picker_size * 0.08f;
11785  float wheel_r_outer = sv_picker_size * 0.50f;
11786  float wheel_r_inner = wheel_r_outer - wheel_thickness;
11787  ImVec2 wheel_center(picker_pos.x + (sv_picker_size + bars_width)*0.5f, picker_pos.y + sv_picker_size*0.5f);
11788 
11789  // Note: the triangle is displayed rotated with triangle_pa pointing to Hue, but most coordinates stays unrotated for logic.
11790  float triangle_r = wheel_r_inner - (int)(sv_picker_size * 0.027f);
11791  ImVec2 triangle_pa = ImVec2(triangle_r, 0.0f); // Hue point.
11792  ImVec2 triangle_pb = ImVec2(triangle_r * -0.5f, triangle_r * -0.866025f); // Black point.
11793  ImVec2 triangle_pc = ImVec2(triangle_r * -0.5f, triangle_r * +0.866025f); // White point.
11794 
11795  float H,S,V;
11796  ColorConvertRGBtoHSV(col[0], col[1], col[2], H, S, V);
11797 
11798  bool value_changed = false, value_changed_h = false, value_changed_sv = false;
11799 
11802  {
11803  // Hue wheel + SV triangle logic
11804  InvisibleButton("hsv", ImVec2(sv_picker_size + style.ItemInnerSpacing.x + bars_width, sv_picker_size));
11805  if (IsItemActive())
11806  {
11807  ImVec2 initial_off = g.IO.MouseClickedPos[0] - wheel_center;
11808  ImVec2 current_off = g.IO.MousePos - wheel_center;
11809  float initial_dist2 = ImLengthSqr(initial_off);
11810  if (initial_dist2 >= (wheel_r_inner-1)*(wheel_r_inner-1) && initial_dist2 <= (wheel_r_outer+1)*(wheel_r_outer+1))
11811  {
11812  // Interactive with Hue wheel
11813  H = atan2f(current_off.y, current_off.x) / IM_PI*0.5f;
11814  if (H < 0.0f)
11815  H += 1.0f;
11816  value_changed = value_changed_h = true;
11817  }
11818  float cos_hue_angle = cosf(-H * 2.0f * IM_PI);
11819  float sin_hue_angle = sinf(-H * 2.0f * IM_PI);
11820  if (ImTriangleContainsPoint(triangle_pa, triangle_pb, triangle_pc, ImRotate(initial_off, cos_hue_angle, sin_hue_angle)))
11821  {
11822  // Interacting with SV triangle
11823  ImVec2 current_off_unrotated = ImRotate(current_off, cos_hue_angle, sin_hue_angle);
11824  if (!ImTriangleContainsPoint(triangle_pa, triangle_pb, triangle_pc, current_off_unrotated))
11825  current_off_unrotated = ImTriangleClosestPoint(triangle_pa, triangle_pb, triangle_pc, current_off_unrotated);
11826  float uu, vv, ww;
11827  ImTriangleBarycentricCoords(triangle_pa, triangle_pb, triangle_pc, current_off_unrotated, uu, vv, ww);
11828  V = ImClamp(1.0f - vv, 0.0001f, 1.0f);
11829  S = ImClamp(uu / V, 0.0001f, 1.0f);
11830  value_changed = value_changed_sv = true;
11831  }
11832  }
11834  OpenPopupOnItemClick("context");
11835  }
11837  {
11838  // SV rectangle logic
11839  InvisibleButton("sv", ImVec2(sv_picker_size, sv_picker_size));
11840  if (IsItemActive())
11841  {
11842  S = ImSaturate((io.MousePos.x - picker_pos.x) / (sv_picker_size-1));
11843  V = 1.0f - ImSaturate((io.MousePos.y - picker_pos.y) / (sv_picker_size-1));
11844  value_changed = value_changed_sv = true;
11845  }
11847  OpenPopupOnItemClick("context");
11848 
11849  // Hue bar logic
11850  SetCursorScreenPos(ImVec2(bar0_pos_x, picker_pos.y));
11851  InvisibleButton("hue", ImVec2(bars_width, sv_picker_size));
11852  if (IsItemActive())
11853  {
11854  H = ImSaturate((io.MousePos.y - picker_pos.y) / (sv_picker_size-1));
11855  value_changed = value_changed_h = true;
11856  }
11857  }
11858 
11859  // Alpha bar logic
11860  if (alpha_bar)
11861  {
11862  SetCursorScreenPos(ImVec2(bar1_pos_x, picker_pos.y));
11863  InvisibleButton("alpha", ImVec2(bars_width, sv_picker_size));
11864  if (IsItemActive())
11865  {
11866  col[3] = 1.0f - ImSaturate((io.MousePos.y - picker_pos.y) / (sv_picker_size-1));
11867  value_changed = true;
11868  }
11869  }
11870  PopItemFlag(); // ImGuiItemFlags_NoNav
11871 
11873  {
11874  SameLine(0, style.ItemInnerSpacing.x);
11875  BeginGroup();
11876  }
11877 
11879  {
11880  const char* label_display_end = FindRenderedTextEnd(label);
11881  if (label != label_display_end)
11882  {
11884  SameLine(0, style.ItemInnerSpacing.x);
11885  TextUnformatted(label, label_display_end);
11886  }
11887  }
11888 
11890  {
11892  ImVec4 col_v4(col[0], col[1], col[2], (flags & ImGuiColorEditFlags_NoAlpha) ? 1.0f : col[3]);
11894  Text("Current");
11896  if (ref_col != NULL)
11897  {
11898  Text("Original");
11899  ImVec4 ref_col_v4(ref_col[0], ref_col[1], ref_col[2], (flags & ImGuiColorEditFlags_NoAlpha) ? 1.0f : ref_col[3]);
11901  {
11902  memcpy(col, ref_col, components * sizeof(float));
11903  value_changed = true;
11904  }
11905  }
11906  PopItemFlag();
11907  EndGroup();
11908  }
11909 
11910  // Convert back color to RGB
11911  if (value_changed_h || value_changed_sv)
11912  ColorConvertHSVtoRGB(H >= 1.0f ? H - 10 * 1e-6f : H, S > 0.0f ? S : 10*1e-6f, V > 0.0f ? V : 1e-6f, col[0], col[1], col[2]);
11913 
11914  // R,G,B and H,S,V slider color editor
11915  if ((flags & ImGuiColorEditFlags_NoInputs) == 0)
11916  {
11917  PushItemWidth((alpha_bar ? bar1_pos_x : bar0_pos_x) + bars_width - picker_pos.x);
11919  ImGuiColorEditFlags sub_flags = (flags & sub_flags_to_forward) | ImGuiColorEditFlags_NoPicker;
11921  value_changed |= ColorEdit4("##rgb", col, sub_flags | ImGuiColorEditFlags_RGB);
11923  value_changed |= ColorEdit4("##hsv", col, sub_flags | ImGuiColorEditFlags_HSV);
11925  value_changed |= ColorEdit4("##hex", col, sub_flags | ImGuiColorEditFlags_HEX);
11926  PopItemWidth();
11927  }
11928 
11929  // Try to cancel hue wrap (after ColorEdit), if any
11930  if (value_changed)
11931  {
11932  float new_H, new_S, new_V;
11933  ColorConvertRGBtoHSV(col[0], col[1], col[2], new_H, new_S, new_V);
11934  if (new_H <= 0 && H > 0)
11935  {
11936  if (new_V <= 0 && V != new_V)
11937  ColorConvertHSVtoRGB(H, S, new_V <= 0 ? V * 0.5f : new_V, col[0], col[1], col[2]);
11938  else if (new_S <= 0)
11939  ColorConvertHSVtoRGB(H, new_S <= 0 ? S * 0.5f : new_S, new_V, col[0], col[1], col[2]);
11940  }
11941  }
11942 
11943  ImVec4 hue_color_f(1, 1, 1, 1); ColorConvertHSVtoRGB(H, 1, 1, hue_color_f.x, hue_color_f.y, hue_color_f.z);
11944  ImU32 hue_color32 = ColorConvertFloat4ToU32(hue_color_f);
11945  ImU32 col32_no_alpha = ColorConvertFloat4ToU32(ImVec4(col[0], col[1], col[2], 1.0f));
11946 
11947  const ImU32 hue_colors[6+1] = { IM_COL32(255,0,0,255), IM_COL32(255,255,0,255), IM_COL32(0,255,0,255), IM_COL32(0,255,255,255), IM_COL32(0,0,255,255), IM_COL32(255,0,255,255), IM_COL32(255,0,0,255) };
11948  ImVec2 sv_cursor_pos;
11949 
11951  {
11952  // Render Hue Wheel
11953  const float aeps = 1.5f / wheel_r_outer; // Half a pixel arc length in radians (2pi cancels out).
11954  const int segment_per_arc = ImMax(4, (int)wheel_r_outer / 12);
11955  for (int n = 0; n < 6; n++)
11956  {
11957  const float a0 = (n) /6.0f * 2.0f * IM_PI - aeps;
11958  const float a1 = (n+1.0f)/6.0f * 2.0f * IM_PI + aeps;
11959  const int vert_start_idx = draw_list->VtxBuffer.Size;
11960  draw_list->PathArcTo(wheel_center, (wheel_r_inner + wheel_r_outer)*0.5f, a0, a1, segment_per_arc);
11961  draw_list->PathStroke(IM_COL32_WHITE, false, wheel_thickness);
11962  const int vert_end_idx = draw_list->VtxBuffer.Size;
11963 
11964  // Paint colors over existing vertices
11965  ImVec2 gradient_p0(wheel_center.x + cosf(a0) * wheel_r_inner, wheel_center.y + sinf(a0) * wheel_r_inner);
11966  ImVec2 gradient_p1(wheel_center.x + cosf(a1) * wheel_r_inner, wheel_center.y + sinf(a1) * wheel_r_inner);
11967  ShadeVertsLinearColorGradientKeepAlpha(draw_list->VtxBuffer.Data + vert_start_idx, draw_list->VtxBuffer.Data + vert_end_idx, gradient_p0, gradient_p1, hue_colors[n], hue_colors[n+1]);
11968  }
11969 
11970  // Render Cursor + preview on Hue Wheel
11971  float cos_hue_angle = cosf(H * 2.0f * IM_PI);
11972  float sin_hue_angle = sinf(H * 2.0f * IM_PI);
11973  ImVec2 hue_cursor_pos(wheel_center.x + cos_hue_angle * (wheel_r_inner+wheel_r_outer)*0.5f, wheel_center.y + sin_hue_angle * (wheel_r_inner+wheel_r_outer)*0.5f);
11974  float hue_cursor_rad = value_changed_h ? wheel_thickness * 0.65f : wheel_thickness * 0.55f;
11975  int hue_cursor_segments = ImClamp((int)(hue_cursor_rad / 1.4f), 9, 32);
11976  draw_list->AddCircleFilled(hue_cursor_pos, hue_cursor_rad, hue_color32, hue_cursor_segments);
11977  draw_list->AddCircle(hue_cursor_pos, hue_cursor_rad+1, IM_COL32(128,128,128,255), hue_cursor_segments);
11978  draw_list->AddCircle(hue_cursor_pos, hue_cursor_rad, IM_COL32_WHITE, hue_cursor_segments);
11979 
11980  // Render SV triangle (rotated according to hue)
11981  ImVec2 tra = wheel_center + ImRotate(triangle_pa, cos_hue_angle, sin_hue_angle);
11982  ImVec2 trb = wheel_center + ImRotate(triangle_pb, cos_hue_angle, sin_hue_angle);
11983  ImVec2 trc = wheel_center + ImRotate(triangle_pc, cos_hue_angle, sin_hue_angle);
11984  ImVec2 uv_white = GetFontTexUvWhitePixel();
11985  draw_list->PrimReserve(6, 6);
11986  draw_list->PrimVtx(tra, uv_white, hue_color32);
11987  draw_list->PrimVtx(trb, uv_white, hue_color32);
11988  draw_list->PrimVtx(trc, uv_white, IM_COL32_WHITE);
11989  draw_list->PrimVtx(tra, uv_white, IM_COL32_BLACK_TRANS);
11990  draw_list->PrimVtx(trb, uv_white, IM_COL32_BLACK);
11991  draw_list->PrimVtx(trc, uv_white, IM_COL32_BLACK_TRANS);
11992  draw_list->AddTriangle(tra, trb, trc, IM_COL32(128,128,128,255), 1.5f);
11993  sv_cursor_pos = ImLerp(ImLerp(trc, tra, ImSaturate(S)), trb, ImSaturate(1 - V));
11994  }
11996  {
11997  // Render SV Square
11998  draw_list->AddRectFilledMultiColor(picker_pos, picker_pos + ImVec2(sv_picker_size,sv_picker_size), IM_COL32_WHITE, hue_color32, hue_color32, IM_COL32_WHITE);
11999  draw_list->AddRectFilledMultiColor(picker_pos, picker_pos + ImVec2(sv_picker_size,sv_picker_size), IM_COL32_BLACK_TRANS, IM_COL32_BLACK_TRANS, IM_COL32_BLACK, IM_COL32_BLACK);
12000  RenderFrameBorder(picker_pos, picker_pos + ImVec2(sv_picker_size,sv_picker_size), 0.0f);
12001  sv_cursor_pos.x = ImClamp((float)(int)(picker_pos.x + ImSaturate(S) * sv_picker_size + 0.5f), picker_pos.x + 2, picker_pos.x + sv_picker_size - 2); // Sneakily prevent the circle to stick out too much
12002  sv_cursor_pos.y = ImClamp((float)(int)(picker_pos.y + ImSaturate(1 - V) * sv_picker_size + 0.5f), picker_pos.y + 2, picker_pos.y + sv_picker_size - 2);
12003 
12004  // Render Hue Bar
12005  for (int i = 0; i < 6; ++i)
12006  draw_list->AddRectFilledMultiColor(ImVec2(bar0_pos_x, picker_pos.y + i * (sv_picker_size / 6)), ImVec2(bar0_pos_x + bars_width, picker_pos.y + (i + 1) * (sv_picker_size / 6)), hue_colors[i], hue_colors[i], hue_colors[i + 1], hue_colors[i + 1]);
12007  float bar0_line_y = (float)(int)(picker_pos.y + H * sv_picker_size + 0.5f);
12008  RenderFrameBorder(ImVec2(bar0_pos_x, picker_pos.y), ImVec2(bar0_pos_x + bars_width, picker_pos.y + sv_picker_size), 0.0f);
12009  RenderArrowsForVerticalBar(draw_list, ImVec2(bar0_pos_x - 1, bar0_line_y), ImVec2(bars_triangles_half_sz + 1, bars_triangles_half_sz), bars_width + 2.0f);
12010  }
12011 
12012  // Render cursor/preview circle (clamp S/V within 0..1 range because floating points colors may lead HSV values to be out of range)
12013  float sv_cursor_rad = value_changed_sv ? 10.0f : 6.0f;
12014  draw_list->AddCircleFilled(sv_cursor_pos, sv_cursor_rad, col32_no_alpha, 12);
12015  draw_list->AddCircle(sv_cursor_pos, sv_cursor_rad+1, IM_COL32(128,128,128,255), 12);
12016  draw_list->AddCircle(sv_cursor_pos, sv_cursor_rad, IM_COL32_WHITE, 12);
12017 
12018  // Render alpha bar
12019  if (alpha_bar)
12020  {
12021  float alpha = ImSaturate(col[3]);
12022  ImRect bar1_bb(bar1_pos_x, picker_pos.y, bar1_pos_x + bars_width, picker_pos.y + sv_picker_size);
12023  RenderColorRectWithAlphaCheckerboard(bar1_bb.Min, bar1_bb.Max, IM_COL32(0,0,0,0), bar1_bb.GetWidth() / 2.0f, ImVec2(0.0f, 0.0f));
12024  draw_list->AddRectFilledMultiColor(bar1_bb.Min, bar1_bb.Max, col32_no_alpha, col32_no_alpha, col32_no_alpha & ~IM_COL32_A_MASK, col32_no_alpha & ~IM_COL32_A_MASK);
12025  float bar1_line_y = (float)(int)(picker_pos.y + (1.0f - alpha) * sv_picker_size + 0.5f);
12026  RenderFrameBorder(bar1_bb.Min, bar1_bb.Max, 0.0f);
12027  RenderArrowsForVerticalBar(draw_list, ImVec2(bar1_pos_x - 1, bar1_line_y), ImVec2(bars_triangles_half_sz + 1, bars_triangles_half_sz), bars_width + 2.0f);
12028  }
12029 
12030  EndGroup();
12031  PopID();
12032 
12033  return value_changed && memcmp(backup_initial_col, col, components * sizeof(float));
12034 }
12035 
12036 // Horizontal separating line.
12038 {
12039  ImGuiWindow* window = GetCurrentWindow();
12040  if (window->SkipItems)
12041  return;
12042  ImGuiContext& g = *GImGui;
12043 
12044  ImGuiWindowFlags flags = 0;
12047  IM_ASSERT(ImIsPowerOfTwo((int)(flags & (ImGuiSeparatorFlags_Horizontal | ImGuiSeparatorFlags_Vertical)))); // Check that only 1 option is selected
12049  {
12051  return;
12052  }
12053 
12054  // Horizontal Separator
12055  if (window->DC.ColumnsSet)
12056  PopClipRect();
12057 
12058  float x1 = window->Pos.x;
12059  float x2 = window->Pos.x + window->Size.x;
12060  if (!window->DC.GroupStack.empty())
12061  x1 += window->DC.IndentX;
12062 
12063  const ImRect bb(ImVec2(x1, window->DC.CursorPos.y), ImVec2(x2, window->DC.CursorPos.y+1.0f));
12064  ItemSize(ImVec2(0.0f, 0.0f)); // NB: we don't provide our width so that it doesn't get feed back into AutoFit, we don't provide height to not alter layout.
12065  if (!ItemAdd(bb, 0))
12066  {
12067  if (window->DC.ColumnsSet)
12069  return;
12070  }
12071 
12072  window->DrawList->AddLine(bb.Min, ImVec2(bb.Max.x,bb.Min.y), GetColorU32(ImGuiCol_Separator));
12073 
12074  if (g.LogEnabled)
12075  LogRenderedText(NULL, IM_NEWLINE "--------------------------------");
12076 
12077  if (window->DC.ColumnsSet)
12078  {
12080  window->DC.ColumnsSet->CellMinY = window->DC.CursorPos.y;
12081  }
12082 }
12083 
12085 {
12086  ImGuiWindow* window = GetCurrentWindow();
12087  if (window->SkipItems)
12088  return;
12089  ImGuiContext& g = *GImGui;
12090 
12091  float y1 = window->DC.CursorPos.y;
12092  float y2 = window->DC.CursorPos.y + window->DC.CurrentLineHeight;
12093  const ImRect bb(ImVec2(window->DC.CursorPos.x, y1), ImVec2(window->DC.CursorPos.x + 1.0f, y2));
12094  ItemSize(ImVec2(bb.GetWidth(), 0.0f));
12095  if (!ItemAdd(bb, 0))
12096  return;
12097 
12098  window->DrawList->AddLine(ImVec2(bb.Min.x, bb.Min.y), ImVec2(bb.Min.x, bb.Max.y), GetColorU32(ImGuiCol_Separator));
12099  if (g.LogEnabled)
12100  LogText(" |");
12101 }
12102 
12103 bool ImGui::SplitterBehavior(ImGuiID id, const ImRect& bb, ImGuiAxis axis, float* size1, float* size2, float min_size1, float min_size2, float hover_extend)
12104 {
12105  ImGuiContext& g = *GImGui;
12106  ImGuiWindow* window = g.CurrentWindow;
12107 
12108  const ImGuiItemFlags item_flags_backup = window->DC.ItemFlags;
12110  bool item_add = ItemAdd(bb, id);
12111  window->DC.ItemFlags = item_flags_backup;
12112  if (!item_add)
12113  return false;
12114 
12115  bool hovered, held;
12116  ImRect bb_interact = bb;
12117  bb_interact.Expand(axis == ImGuiAxis_Y ? ImVec2(0.0f, hover_extend) : ImVec2(hover_extend, 0.0f));
12119  if (g.ActiveId != id)
12121 
12122  if (held || (g.HoveredId == id && g.HoveredIdPreviousFrame == id))
12124 
12125  ImRect bb_render = bb;
12126  if (held)
12127  {
12128  ImVec2 mouse_delta_2d = g.IO.MousePos - g.ActiveIdClickOffset - bb_interact.Min;
12129  float mouse_delta = (axis == ImGuiAxis_Y) ? mouse_delta_2d.y : mouse_delta_2d.x;
12130 
12131  // Minimum pane size
12132  if (mouse_delta < min_size1 - *size1)
12133  mouse_delta = min_size1 - *size1;
12134  if (mouse_delta > *size2 - min_size2)
12135  mouse_delta = *size2 - min_size2;
12136 
12137  // Apply resize
12138  *size1 += mouse_delta;
12139  *size2 -= mouse_delta;
12140  bb_render.Translate((axis == ImGuiAxis_X) ? ImVec2(mouse_delta, 0.0f) : ImVec2(0.0f, mouse_delta));
12141  }
12142 
12143  // Render
12145  window->DrawList->AddRectFilled(bb_render.Min, bb_render.Max, col, g.Style.FrameRounding);
12146 
12147  return held;
12148 }
12149 
12151 {
12152  ImGuiWindow* window = GetCurrentWindow();
12153  if (window->SkipItems)
12154  return;
12155  ItemSize(ImVec2(0,0));
12156 }
12157 
12159 {
12160  ImGuiWindow* window = GetCurrentWindow();
12161  if (window->SkipItems)
12162  return;
12163 
12164  const ImRect bb(window->DC.CursorPos, window->DC.CursorPos + size);
12165  ItemSize(bb);
12166  ItemAdd(bb, 0);
12167 }
12168 
12170 {
12171  ImGuiWindow* window = GetCurrentWindowRead();
12172  return window->ClipRect.Overlaps(ImRect(window->DC.CursorPos, window->DC.CursorPos + size));
12173 }
12174 
12175 bool ImGui::IsRectVisible(const ImVec2& rect_min, const ImVec2& rect_max)
12176 {
12177  ImGuiWindow* window = GetCurrentWindowRead();
12178  return window->ClipRect.Overlaps(ImRect(rect_min, rect_max));
12179 }
12180 
12181 // Lock horizontal starting position + capture group bounding box into one "item" (so you can use IsItemHovered() or layout primitives such as SameLine() on whole group, etc.)
12183 {
12184  ImGuiWindow* window = GetCurrentWindow();
12185 
12186  window->DC.GroupStack.resize(window->DC.GroupStack.Size + 1);
12187  ImGuiGroupData& group_data = window->DC.GroupStack.back();
12188  group_data.BackupCursorPos = window->DC.CursorPos;
12189  group_data.BackupCursorMaxPos = window->DC.CursorMaxPos;
12190  group_data.BackupIndentX = window->DC.IndentX;
12191  group_data.BackupGroupOffsetX = window->DC.GroupOffsetX;
12192  group_data.BackupCurrentLineHeight = window->DC.CurrentLineHeight;
12194  group_data.BackupLogLinePosY = window->DC.LogLinePosY;
12196  group_data.AdvanceCursor = true;
12197 
12198  window->DC.GroupOffsetX = window->DC.CursorPos.x - window->Pos.x - window->DC.ColumnsOffsetX;
12199  window->DC.IndentX = window->DC.GroupOffsetX;
12200  window->DC.CursorMaxPos = window->DC.CursorPos;
12201  window->DC.CurrentLineHeight = 0.0f;
12202  window->DC.LogLinePosY = window->DC.CursorPos.y - 9999.0f;
12203 }
12204 
12206 {
12207  ImGuiContext& g = *GImGui;
12208  ImGuiWindow* window = GetCurrentWindow();
12209 
12210  IM_ASSERT(!window->DC.GroupStack.empty()); // Mismatched BeginGroup()/EndGroup() calls
12211 
12212  ImGuiGroupData& group_data = window->DC.GroupStack.back();
12213 
12214  ImRect group_bb(group_data.BackupCursorPos, window->DC.CursorMaxPos);
12215  group_bb.Max = ImMax(group_bb.Min, group_bb.Max);
12216 
12217  window->DC.CursorPos = group_data.BackupCursorPos;
12218  window->DC.CursorMaxPos = ImMax(group_data.BackupCursorMaxPos, window->DC.CursorMaxPos);
12219  window->DC.CurrentLineHeight = group_data.BackupCurrentLineHeight;
12220  window->DC.CurrentLineTextBaseOffset = group_data.BackupCurrentLineTextBaseOffset;
12221  window->DC.IndentX = group_data.BackupIndentX;
12222  window->DC.GroupOffsetX = group_data.BackupGroupOffsetX;
12223  window->DC.LogLinePosY = window->DC.CursorPos.y - 9999.0f;
12224 
12225  if (group_data.AdvanceCursor)
12226  {
12227  window->DC.CurrentLineTextBaseOffset = ImMax(window->DC.PrevLineTextBaseOffset, group_data.BackupCurrentLineTextBaseOffset); // FIXME: Incorrect, we should grab the base offset from the *first line* of the group but it is hard to obtain now.
12228  ItemSize(group_bb.GetSize(), group_data.BackupCurrentLineTextBaseOffset);
12229  ItemAdd(group_bb, 0);
12230  }
12231 
12232  // If the current ActiveId was declared within the boundary of our group, we copy it to LastItemId so IsItemActive() will be functional on the entire group.
12233  // It would be be neater if we replaced window.DC.LastItemId by e.g. 'bool LastItemIsActive', but if you search for LastItemId you'll notice it is only used in that context.
12234  const bool active_id_within_group = (!group_data.BackupActiveIdIsAlive && g.ActiveIdIsAlive && g.ActiveId && g.ActiveIdWindow->RootWindow == window->RootWindow);
12235  if (active_id_within_group)
12236  window->DC.LastItemId = g.ActiveId;
12237  window->DC.LastItemRect = group_bb;
12238 
12239  window->DC.GroupStack.pop_back();
12240 
12241  //window->DrawList->AddRect(group_bb.Min, group_bb.Max, IM_COL32(255,0,255,255)); // [Debug]
12242 }
12243 
12244 // Gets back to previous line and continue with horizontal layout
12245 // pos_x == 0 : follow right after previous item
12246 // pos_x != 0 : align to specified x position (relative to window/group left)
12247 // spacing_w < 0 : use default spacing if pos_x == 0, no spacing if pos_x != 0
12248 // spacing_w >= 0 : enforce spacing amount
12249 void ImGui::SameLine(float pos_x, float spacing_w)
12250 {
12251  ImGuiWindow* window = GetCurrentWindow();
12252  if (window->SkipItems)
12253  return;
12254 
12255  ImGuiContext& g = *GImGui;
12256  if (pos_x != 0.0f)
12257  {
12258  if (spacing_w < 0.0f) spacing_w = 0.0f;
12259  window->DC.CursorPos.x = window->Pos.x - window->Scroll.x + pos_x + spacing_w + window->DC.GroupOffsetX + window->DC.ColumnsOffsetX;
12260  window->DC.CursorPos.y = window->DC.CursorPosPrevLine.y;
12261  }
12262  else
12263  {
12264  if (spacing_w < 0.0f) spacing_w = g.Style.ItemSpacing.x;
12265  window->DC.CursorPos.x = window->DC.CursorPosPrevLine.x + spacing_w;
12266  window->DC.CursorPos.y = window->DC.CursorPosPrevLine.y;
12267  }
12268  window->DC.CurrentLineHeight = window->DC.PrevLineHeight;
12270 }
12271 
12273 {
12274  ImGuiWindow* window = GetCurrentWindow();
12275  if (window->SkipItems)
12276  return;
12277 
12278  ImGuiContext& g = *GImGui;
12279  const ImGuiLayoutType backup_layout_type = window->DC.LayoutType;
12281  if (window->DC.CurrentLineHeight > 0.0f) // In the event that we are on a line with items that is smaller that FontSize high, we will preserve its height.
12282  ItemSize(ImVec2(0,0));
12283  else
12284  ItemSize(ImVec2(0.0f, g.FontSize));
12285  window->DC.LayoutType = backup_layout_type;
12286 }
12287 
12289 {
12290  ImGuiWindow* window = GetCurrentWindow();
12291  if (window->SkipItems || window->DC.ColumnsSet == NULL)
12292  return;
12293 
12294  ImGuiContext& g = *GImGui;
12295  PopItemWidth();
12296  PopClipRect();
12297 
12298  ImGuiColumnsSet* columns = window->DC.ColumnsSet;
12299  columns->CellMaxY = ImMax(columns->CellMaxY, window->DC.CursorPos.y);
12300  if (++columns->Current < columns->Count)
12301  {
12302  // Columns 1+ cancel out IndentX
12303  window->DC.ColumnsOffsetX = GetColumnOffset(columns->Current) - window->DC.IndentX + g.Style.ItemSpacing.x;
12304  window->DrawList->ChannelsSetCurrent(columns->Current);
12305  }
12306  else
12307  {
12308  window->DC.ColumnsOffsetX = 0.0f;
12309  window->DrawList->ChannelsSetCurrent(0);
12310  columns->Current = 0;
12311  columns->CellMinY = columns->CellMaxY;
12312  }
12313  window->DC.CursorPos.x = (float)(int)(window->Pos.x + window->DC.IndentX + window->DC.ColumnsOffsetX);
12314  window->DC.CursorPos.y = columns->CellMinY;
12315  window->DC.CurrentLineHeight = 0.0f;
12316  window->DC.CurrentLineTextBaseOffset = 0.0f;
12317 
12319  PushItemWidth(GetColumnWidth() * 0.65f); // FIXME: Move on columns setup
12320 }
12321 
12323 {
12324  ImGuiWindow* window = GetCurrentWindowRead();
12325  return window->DC.ColumnsSet ? window->DC.ColumnsSet->Current : 0;
12326 }
12327 
12329 {
12330  ImGuiWindow* window = GetCurrentWindowRead();
12331  return window->DC.ColumnsSet ? window->DC.ColumnsSet->Count : 1;
12332 }
12333 
12334 static float OffsetNormToPixels(const ImGuiColumnsSet* columns, float offset_norm)
12335 {
12336  return offset_norm * (columns->MaxX - columns->MinX);
12337 }
12338 
12339 static float PixelsToOffsetNorm(const ImGuiColumnsSet* columns, float offset)
12340 {
12341  return offset / (columns->MaxX - columns->MinX);
12342 }
12343 
12344 static inline float GetColumnsRectHalfWidth() { return 4.0f; }
12345 
12346 static float GetDraggedColumnOffset(ImGuiColumnsSet* columns, int column_index)
12347 {
12348  // Active (dragged) column always follow mouse. The reason we need this is that dragging a column to the right edge of an auto-resizing
12349  // window creates a feedback loop because we store normalized positions. So while dragging we enforce absolute positioning.
12350  ImGuiContext& g = *GImGui;
12351  ImGuiWindow* window = g.CurrentWindow;
12352  IM_ASSERT(column_index > 0); // We cannot drag column 0. If you get this assert you may have a conflict between the ID of your columns and another widgets.
12353  IM_ASSERT(g.ActiveId == columns->ID + ImGuiID(column_index));
12354 
12355  float x = g.IO.MousePos.x - g.ActiveIdClickOffset.x + GetColumnsRectHalfWidth() - window->Pos.x;
12356  x = ImMax(x, ImGui::GetColumnOffset(column_index - 1) + g.Style.ColumnsMinSpacing);
12357  if ((columns->Flags & ImGuiColumnsFlags_NoPreserveWidths))
12358  x = ImMin(x, ImGui::GetColumnOffset(column_index + 1) - g.Style.ColumnsMinSpacing);
12359 
12360  return x;
12361 }
12362 
12363 float ImGui::GetColumnOffset(int column_index)
12364 {
12365  ImGuiWindow* window = GetCurrentWindowRead();
12366  ImGuiColumnsSet* columns = window->DC.ColumnsSet;
12367  IM_ASSERT(columns != NULL);
12368 
12369  if (column_index < 0)
12370  column_index = columns->Current;
12371  IM_ASSERT(column_index < columns->Columns.Size);
12372 
12373  /*
12374  if (g.ActiveId)
12375  {
12376  ImGuiContext& g = *GImGui;
12377  const ImGuiID column_id = columns->ColumnsSetId + ImGuiID(column_index);
12378  if (g.ActiveId == column_id)
12379  return GetDraggedColumnOffset(columns, column_index);
12380  }
12381  */
12382 
12383  const float t = columns->Columns[column_index].OffsetNorm;
12384  const float x_offset = ImLerp(columns->MinX, columns->MaxX, t);
12385  return x_offset;
12386 }
12387 
12388 static float GetColumnWidthEx(ImGuiColumnsSet* columns, int column_index, bool before_resize = false)
12389 {
12390  if (column_index < 0)
12391  column_index = columns->Current;
12392 
12393  float offset_norm;
12394  if (before_resize)
12395  offset_norm = columns->Columns[column_index + 1].OffsetNormBeforeResize - columns->Columns[column_index].OffsetNormBeforeResize;
12396  else
12397  offset_norm = columns->Columns[column_index + 1].OffsetNorm - columns->Columns[column_index].OffsetNorm;
12398  return OffsetNormToPixels(columns, offset_norm);
12399 }
12400 
12401 float ImGui::GetColumnWidth(int column_index)
12402 {
12403  ImGuiWindow* window = GetCurrentWindowRead();
12404  ImGuiColumnsSet* columns = window->DC.ColumnsSet;
12405  IM_ASSERT(columns != NULL);
12406 
12407  if (column_index < 0)
12408  column_index = columns->Current;
12409  return OffsetNormToPixels(columns, columns->Columns[column_index + 1].OffsetNorm - columns->Columns[column_index].OffsetNorm);
12410 }
12411 
12412 void ImGui::SetColumnOffset(int column_index, float offset)
12413 {
12414  ImGuiContext& g = *GImGui;
12415  ImGuiWindow* window = g.CurrentWindow;
12416  ImGuiColumnsSet* columns = window->DC.ColumnsSet;
12417  IM_ASSERT(columns != NULL);
12418 
12419  if (column_index < 0)
12420  column_index = columns->Current;
12421  IM_ASSERT(column_index < columns->Columns.Size);
12422 
12423  const bool preserve_width = !(columns->Flags & ImGuiColumnsFlags_NoPreserveWidths) && (column_index < columns->Count-1);
12424  const float width = preserve_width ? GetColumnWidthEx(columns, column_index, columns->IsBeingResized) : 0.0f;
12425 
12426  if (!(columns->Flags & ImGuiColumnsFlags_NoForceWithinWindow))
12427  offset = ImMin(offset, columns->MaxX - g.Style.ColumnsMinSpacing * (columns->Count - column_index));
12428  columns->Columns[column_index].OffsetNorm = PixelsToOffsetNorm(columns, offset - columns->MinX);
12429 
12430  if (preserve_width)
12431  SetColumnOffset(column_index + 1, offset + ImMax(g.Style.ColumnsMinSpacing, width));
12432 }
12433 
12434 void ImGui::SetColumnWidth(int column_index, float width)
12435 {
12436  ImGuiWindow* window = GetCurrentWindowRead();
12437  ImGuiColumnsSet* columns = window->DC.ColumnsSet;
12438  IM_ASSERT(columns != NULL);
12439 
12440  if (column_index < 0)
12441  column_index = columns->Current;
12442  SetColumnOffset(column_index + 1, GetColumnOffset(column_index) + width);
12443 }
12444 
12445 void ImGui::PushColumnClipRect(int column_index)
12446 {
12447  ImGuiWindow* window = GetCurrentWindowRead();
12448  ImGuiColumnsSet* columns = window->DC.ColumnsSet;
12449  if (column_index < 0)
12450  column_index = columns->Current;
12451 
12452  PushClipRect(columns->Columns[column_index].ClipRect.Min, columns->Columns[column_index].ClipRect.Max, false);
12453 }
12454 
12456 {
12457  for (int n = 0; n < window->ColumnsStorage.Size; n++)
12458  if (window->ColumnsStorage[n].ID == id)
12459  return &window->ColumnsStorage[n];
12460 
12462  ImGuiColumnsSet* columns = &window->ColumnsStorage.back();
12463  columns->ID = id;
12464  return columns;
12465 }
12466 
12467 void ImGui::BeginColumns(const char* str_id, int columns_count, ImGuiColumnsFlags flags)
12468 {
12469  ImGuiContext& g = *GImGui;
12470  ImGuiWindow* window = GetCurrentWindow();
12471 
12472  IM_ASSERT(columns_count > 1);
12473  IM_ASSERT(window->DC.ColumnsSet == NULL); // Nested columns are currently not supported
12474 
12475  // Differentiate column ID with an arbitrary prefix for cases where users name their columns set the same as another widget.
12476  // In addition, when an identifier isn't explicitly provided we include the number of columns in the hash to make it uniquer.
12477  PushID(0x11223347 + (str_id ? 0 : columns_count));
12478  ImGuiID id = window->GetID(str_id ? str_id : "columns");
12479  PopID();
12480 
12481  // Acquire storage for the columns set
12482  ImGuiColumnsSet* columns = FindOrAddColumnsSet(window, id);
12483  IM_ASSERT(columns->ID == id);
12484  columns->Current = 0;
12485  columns->Count = columns_count;
12486  columns->Flags = flags;
12487  window->DC.ColumnsSet = columns;
12488 
12489  // Set state for first column
12490  const float content_region_width = (window->SizeContentsExplicit.x != 0.0f) ? (window->SizeContentsExplicit.x) : (window->Size.x -window->ScrollbarSizes.x);
12491  columns->MinX = window->DC.IndentX - g.Style.ItemSpacing.x; // Lock our horizontal range
12492  //column->MaxX = content_region_width - window->Scroll.x - ((window->Flags & ImGuiWindowFlags_NoScrollbar) ? 0 : g.Style.ScrollbarSize);// - window->WindowPadding().x;
12493  columns->MaxX = content_region_width - window->Scroll.x;
12494  columns->StartPosY = window->DC.CursorPos.y;
12495  columns->StartMaxPosX = window->DC.CursorMaxPos.x;
12496  columns->CellMinY = columns->CellMaxY = window->DC.CursorPos.y;
12497  window->DC.ColumnsOffsetX = 0.0f;
12498  window->DC.CursorPos.x = (float)(int)(window->Pos.x + window->DC.IndentX + window->DC.ColumnsOffsetX);
12499 
12500  // Clear data if columns count changed
12501  if (columns->Columns.Size != 0 && columns->Columns.Size != columns_count + 1)
12502  columns->Columns.resize(0);
12503 
12504  // Initialize defaults
12505  columns->IsFirstFrame = (columns->Columns.Size == 0);
12506  if (columns->Columns.Size == 0)
12507  {
12508  columns->Columns.reserve(columns_count + 1);
12509  for (int n = 0; n < columns_count + 1; n++)
12510  {
12512  column.OffsetNorm = n / (float)columns_count;
12513  columns->Columns.push_back(column);
12514  }
12515  }
12516 
12517  for (int n = 0; n < columns_count + 1; n++)
12518  {
12519  // Clamp position
12520  ImGuiColumnData* column = &columns->Columns[n];
12521  float t = column->OffsetNorm;
12522  if (!(columns->Flags & ImGuiColumnsFlags_NoForceWithinWindow))
12523  t = ImMin(t, PixelsToOffsetNorm(columns, (columns->MaxX - columns->MinX) - g.Style.ColumnsMinSpacing * (columns->Count - n)));
12524  column->OffsetNorm = t;
12525 
12526  if (n == columns_count)
12527  continue;
12528 
12529  // Compute clipping rectangle
12530  float clip_x1 = ImFloor(0.5f + window->Pos.x + GetColumnOffset(n) - 1.0f);
12531  float clip_x2 = ImFloor(0.5f + window->Pos.x + GetColumnOffset(n + 1) - 1.0f);
12532  column->ClipRect = ImRect(clip_x1, -FLT_MAX, clip_x2, +FLT_MAX);
12533  column->ClipRect.ClipWith(window->ClipRect);
12534  }
12535 
12536  window->DrawList->ChannelsSplit(columns->Count);
12538  PushItemWidth(GetColumnWidth() * 0.65f);
12539 }
12540 
12542 {
12543  ImGuiContext& g = *GImGui;
12544  ImGuiWindow* window = GetCurrentWindow();
12545  ImGuiColumnsSet* columns = window->DC.ColumnsSet;
12546  IM_ASSERT(columns != NULL);
12547 
12548  PopItemWidth();
12549  PopClipRect();
12550  window->DrawList->ChannelsMerge();
12551 
12552  columns->CellMaxY = ImMax(columns->CellMaxY, window->DC.CursorPos.y);
12553  window->DC.CursorPos.y = columns->CellMaxY;
12555  window->DC.CursorMaxPos.x = ImMax(columns->StartMaxPosX, columns->MaxX); // Restore cursor max pos, as columns don't grow parent
12556 
12557  // Draw columns borders and handle resize
12558  bool is_being_resized = false;
12559  if (!(columns->Flags & ImGuiColumnsFlags_NoBorder) && !window->SkipItems)
12560  {
12561  const float y1 = columns->StartPosY;
12562  const float y2 = window->DC.CursorPos.y;
12563  int dragging_column = -1;
12564  for (int n = 1; n < columns->Count; n++)
12565  {
12566  float x = window->Pos.x + GetColumnOffset(n);
12567  const ImGuiID column_id = columns->ID + ImGuiID(n);
12568  const float column_hw = GetColumnsRectHalfWidth(); // Half-width for interaction
12569  const ImRect column_rect(ImVec2(x - column_hw, y1), ImVec2(x + column_hw, y2));
12570  KeepAliveID(column_id);
12571  if (IsClippedEx(column_rect, column_id, false))
12572  continue;
12573 
12574  bool hovered = false, held = false;
12575  if (!(columns->Flags & ImGuiColumnsFlags_NoResize))
12576  {
12577  ButtonBehavior(column_rect, column_id, &hovered, &held);
12578  if (hovered || held)
12579  g.MouseCursor = ImGuiMouseCursor_ResizeEW;
12580  if (held && !(columns->Columns[n].Flags & ImGuiColumnsFlags_NoResize))
12581  dragging_column = n;
12582  }
12583 
12584  // Draw column (we clip the Y boundaries CPU side because very long triangles are mishandled by some GPU drivers.)
12586  const float xi = (float)(int)x;
12587  window->DrawList->AddLine(ImVec2(xi, ImMax(y1 + 1.0f, window->ClipRect.Min.y)), ImVec2(xi, ImMin(y2, window->ClipRect.Max.y)), col);
12588  }
12589 
12590  // Apply dragging after drawing the column lines, so our rendered lines are in sync with how items were displayed during the frame.
12591  if (dragging_column != -1)
12592  {
12593  if (!columns->IsBeingResized)
12594  for (int n = 0; n < columns->Count + 1; n++)
12595  columns->Columns[n].OffsetNormBeforeResize = columns->Columns[n].OffsetNorm;
12596  columns->IsBeingResized = is_being_resized = true;
12597  float x = GetDraggedColumnOffset(columns, dragging_column);
12598  SetColumnOffset(dragging_column, x);
12599  }
12600  }
12601  columns->IsBeingResized = is_being_resized;
12602 
12603  window->DC.ColumnsSet = NULL;
12604  window->DC.ColumnsOffsetX = 0.0f;
12605  window->DC.CursorPos.x = (float)(int)(window->Pos.x + window->DC.IndentX + window->DC.ColumnsOffsetX);
12606 }
12607 
12608 // [2017/12: This is currently the only public API, while we are working on making BeginColumns/EndColumns user-facing]
12609 void ImGui::Columns(int columns_count, const char* id, bool border)
12610 {
12611  ImGuiWindow* window = GetCurrentWindow();
12612  IM_ASSERT(columns_count >= 1);
12613  if (window->DC.ColumnsSet != NULL && window->DC.ColumnsSet->Count != columns_count)
12614  EndColumns();
12615 
12617  //flags |= ImGuiColumnsFlags_NoPreserveWidths; // NB: Legacy behavior
12618  if (columns_count != 1)
12619  BeginColumns(id, columns_count, flags);
12620 }
12621 
12622 void ImGui::Indent(float indent_w)
12623 {
12624  ImGuiContext& g = *GImGui;
12625  ImGuiWindow* window = GetCurrentWindow();
12626  window->DC.IndentX += (indent_w != 0.0f) ? indent_w : g.Style.IndentSpacing;
12627  window->DC.CursorPos.x = window->Pos.x + window->DC.IndentX + window->DC.ColumnsOffsetX;
12628 }
12629 
12630 void ImGui::Unindent(float indent_w)
12631 {
12632  ImGuiContext& g = *GImGui;
12633  ImGuiWindow* window = GetCurrentWindow();
12634  window->DC.IndentX -= (indent_w != 0.0f) ? indent_w : g.Style.IndentSpacing;
12635  window->DC.CursorPos.x = window->Pos.x + window->DC.IndentX + window->DC.ColumnsOffsetX;
12636 }
12637 
12638 void ImGui::TreePush(const char* str_id)
12639 {
12640  ImGuiWindow* window = GetCurrentWindow();
12641  Indent();
12642  window->DC.TreeDepth++;
12643  PushID(str_id ? str_id : "#TreePush");
12644 }
12645 
12646 void ImGui::TreePush(const void* ptr_id)
12647 {
12648  ImGuiWindow* window = GetCurrentWindow();
12649  Indent();
12650  window->DC.TreeDepth++;
12651  PushID(ptr_id ? ptr_id : (const void*)"#TreePush");
12652 }
12653 
12655 {
12656  ImGuiWindow* window = GetCurrentWindow();
12657  Indent();
12658  window->DC.TreeDepth++;
12659  window->IDStack.push_back(id);
12660 }
12661 
12663 {
12664  ImGuiContext& g = *GImGui;
12665  ImGuiWindow* window = g.CurrentWindow;
12666  Unindent();
12667 
12668  window->DC.TreeDepth--;
12669  if (g.NavMoveDir == ImGuiDir_Left && g.NavWindow == window && NavMoveRequestButNoResultYet())
12670  if (g.NavIdIsAlive && (window->DC.TreeDepthMayJumpToParentOnPop & (1 << window->DC.TreeDepth)))
12671  {
12672  SetNavID(window->IDStack.back(), g.NavLayer);
12674  }
12675  window->DC.TreeDepthMayJumpToParentOnPop &= (1 << window->DC.TreeDepth) - 1;
12676 
12677  PopID();
12678 }
12679 
12680 void ImGui::Value(const char* prefix, bool b)
12681 {
12682  Text("%s: %s", prefix, (b ? "true" : "false"));
12683 }
12684 
12685 void ImGui::Value(const char* prefix, int v)
12686 {
12687  Text("%s: %d", prefix, v);
12688 }
12689 
12690 void ImGui::Value(const char* prefix, unsigned int v)
12691 {
12692  Text("%s: %d", prefix, v);
12693 }
12694 
12695 void ImGui::Value(const char* prefix, float v, const char* float_format)
12696 {
12697  if (float_format)
12698  {
12699  char fmt[64];
12700  ImFormatString(fmt, IM_ARRAYSIZE(fmt), "%%s: %s", float_format);
12701  Text(fmt, prefix, v);
12702  }
12703  else
12704  {
12705  Text("%s: %.3f", prefix, v);
12706  }
12707 }
12708 
12709 //-----------------------------------------------------------------------------
12710 // DRAG AND DROP
12711 //-----------------------------------------------------------------------------
12712 
12714 {
12715  ImGuiContext& g = *GImGui;
12716  g.DragDropActive = false;
12717  g.DragDropPayload.Clear();
12718  g.DragDropAcceptIdCurr = g.DragDropAcceptIdPrev = 0;
12719  g.DragDropAcceptIdCurrRectSurface = FLT_MAX;
12720  g.DragDropAcceptFrameCount = -1;
12721 }
12722 
12723 // Call when current ID is active.
12724 // When this returns true you need to: a) call SetDragDropPayload() exactly once, b) you may render the payload visual/description, c) call EndDragDropSource()
12726 {
12727  ImGuiContext& g = *GImGui;
12728  ImGuiWindow* window = g.CurrentWindow;
12729 
12730  bool source_drag_active = false;
12731  ImGuiID source_id = 0;
12732  ImGuiID source_parent_id = 0;
12733  int mouse_button = 0;
12735  {
12736  source_id = window->DC.LastItemId;
12737  if (source_id != 0 && g.ActiveId != source_id) // Early out for most common case
12738  return false;
12739  if (g.IO.MouseDown[mouse_button] == false)
12740  return false;
12741 
12742  if (source_id == 0)
12743  {
12744  // If you want to use BeginDragDropSource() on an item with no unique identifier for interaction, such as Text() or Image(), you need to:
12745  // A) Read the explanation below, B) Use the ImGuiDragDropFlags_SourceAllowNullID flag, C) Swallow your programmer pride.
12747  {
12748  IM_ASSERT(0);
12749  return false;
12750  }
12751 
12752  // Magic fallback (=somehow reprehensible) to handle items with no assigned ID, e.g. Text(), Image()
12753  // We build a throwaway ID based on current ID stack + relative AABB of items in window.
12754  // THE IDENTIFIER WON'T SURVIVE ANY REPOSITIONING OF THE WIDGET, so if your widget moves your dragging operation will be canceled.
12755  // We don't need to maintain/call ClearActiveID() as releasing the button will early out this function and trigger !ActiveIdIsAlive.
12756  bool is_hovered = (window->DC.LastItemStatusFlags & ImGuiItemStatusFlags_HoveredRect) != 0;
12757  if (!is_hovered && (g.ActiveId == 0 || g.ActiveIdWindow != window))
12758  return false;
12759  source_id = window->DC.LastItemId = window->GetIDFromRectangle(window->DC.LastItemRect);
12760  if (is_hovered)
12761  SetHoveredID(source_id);
12762  if (is_hovered && g.IO.MouseClicked[mouse_button])
12763  {
12764  SetActiveID(source_id, window);
12765  FocusWindow(window);
12766  }
12767  if (g.ActiveId == source_id) // Allow the underlying widget to display/return hovered during the mouse release frame, else we would get a flicker.
12768  g.ActiveIdAllowOverlap = is_hovered;
12769  }
12770  if (g.ActiveId != source_id)
12771  return false;
12772  source_parent_id = window->IDStack.back();
12773  source_drag_active = IsMouseDragging(mouse_button);
12774  }
12775  else
12776  {
12777  window = NULL;
12778  source_id = ImHash("#SourceExtern", 0);
12779  source_drag_active = true;
12780  }
12781 
12782  if (source_drag_active)
12783  {
12784  if (!g.DragDropActive)
12785  {
12786  IM_ASSERT(source_id != 0);
12787  ClearDragDrop();
12788  ImGuiPayload& payload = g.DragDropPayload;
12789  payload.SourceId = source_id;
12790  payload.SourceParentId = source_parent_id;
12791  g.DragDropActive = true;
12792  g.DragDropSourceFlags = flags;
12793  g.DragDropMouseButton = mouse_button;
12794  }
12795 
12797  {
12798  // FIXME-DRAG
12799  //SetNextWindowPos(g.IO.MousePos - g.ActiveIdClickOffset - g.Style.WindowPadding);
12800  //PushStyleVar(ImGuiStyleVar_Alpha, g.Style.Alpha * 0.60f); // This is better but e.g ColorButton with checkboard has issue with transparent colors :(
12801  SetNextWindowPos(g.IO.MousePos);
12803  BeginTooltip();
12804  }
12805 
12808 
12809  return true;
12810  }
12811  return false;
12812 }
12813 
12815 {
12816  ImGuiContext& g = *GImGui;
12817  IM_ASSERT(g.DragDropActive);
12818 
12819  if (!(g.DragDropSourceFlags & ImGuiDragDropFlags_SourceNoPreviewTooltip))
12820  {
12821  EndTooltip();
12822  PopStyleColor();
12823  //PopStyleVar();
12824  }
12825 
12826  // Discard the drag if have not called SetDragDropPayload()
12827  if (g.DragDropPayload.DataFrameCount == -1)
12828  ClearDragDrop();
12829 }
12830 
12831 // Use 'cond' to choose to submit payload on drag start or every frame
12832 bool ImGui::SetDragDropPayload(const char* type, const void* data, size_t data_size, ImGuiCond cond)
12833 {
12834  ImGuiContext& g = *GImGui;
12835  ImGuiPayload& payload = g.DragDropPayload;
12836  if (cond == 0)
12837  cond = ImGuiCond_Always;
12838 
12839  IM_ASSERT(type != NULL);
12840  IM_ASSERT(strlen(type) < IM_ARRAYSIZE(payload.DataType) && "Payload type can be at most 12 characters long");
12841  IM_ASSERT((data != NULL && data_size > 0) || (data == NULL && data_size == 0));
12842  IM_ASSERT(cond == ImGuiCond_Always || cond == ImGuiCond_Once);
12843  IM_ASSERT(payload.SourceId != 0); // Not called between BeginDragDropSource() and EndDragDropSource()
12844 
12845  if (cond == ImGuiCond_Always || payload.DataFrameCount == -1)
12846  {
12847  // Copy payload
12848  ImStrncpy(payload.DataType, type, IM_ARRAYSIZE(payload.DataType));
12849  g.DragDropPayloadBufHeap.resize(0);
12850  if (data_size > sizeof(g.DragDropPayloadBufLocal))
12851  {
12852  // Store in heap
12853  g.DragDropPayloadBufHeap.resize((int)data_size);
12854  payload.Data = g.DragDropPayloadBufHeap.Data;
12855  memcpy((void*)payload.Data, data, data_size);
12856  }
12857  else if (data_size > 0)
12858  {
12859  // Store locally
12860  memset(&g.DragDropPayloadBufLocal, 0, sizeof(g.DragDropPayloadBufLocal));
12861  payload.Data = g.DragDropPayloadBufLocal;
12862  memcpy((void*)payload.Data, data, data_size);
12863  }
12864  else
12865  {
12866  payload.Data = NULL;
12867  }
12868  payload.DataSize = (int)data_size;
12869  }
12870  payload.DataFrameCount = g.FrameCount;
12871 
12872  return (g.DragDropAcceptFrameCount == g.FrameCount) || (g.DragDropAcceptFrameCount == g.FrameCount - 1);
12873 }
12874 
12876 {
12877  ImGuiContext& g = *GImGui;
12878  if (!g.DragDropActive)
12879  return false;
12880 
12881  ImGuiWindow* window = g.CurrentWindow;
12882  if (g.HoveredWindow == NULL || window->RootWindow != g.HoveredWindow->RootWindow)
12883  return false;
12884  IM_ASSERT(id != 0);
12885  if (!IsMouseHoveringRect(bb.Min, bb.Max) || (id == g.DragDropPayload.SourceId))
12886  return false;
12887 
12888  g.DragDropTargetRect = bb;
12889  g.DragDropTargetId = id;
12890  return true;
12891 }
12892 
12893 // We don't use BeginDragDropTargetCustom() and duplicate its code because:
12894 // 1) we use LastItemRectHoveredRect which handles items that pushes a temporarily clip rectangle in their code. Calling BeginDragDropTargetCustom(LastItemRect) would not handle them.
12895 // 2) and it's faster. as this code may be very frequently called, we want to early out as fast as we can.
12896 // Also note how the HoveredWindow test is positioned differently in both functions (in both functions we optimize for the cheapest early out case)
12898 {
12899  ImGuiContext& g = *GImGui;
12900  if (!g.DragDropActive)
12901  return false;
12902 
12903  ImGuiWindow* window = g.CurrentWindow;
12905  return false;
12906  if (g.HoveredWindow == NULL || window->RootWindow != g.HoveredWindow->RootWindow)
12907  return false;
12908 
12909  const ImRect& display_rect = (window->DC.LastItemStatusFlags & ImGuiItemStatusFlags_HasDisplayRect) ? window->DC.LastItemDisplayRect : window->DC.LastItemRect;
12910  ImGuiID id = window->DC.LastItemId;
12911  if (id == 0)
12912  id = window->GetIDFromRectangle(display_rect);
12913  if (g.DragDropPayload.SourceId == id)
12914  return false;
12915 
12916  g.DragDropTargetRect = display_rect;
12917  g.DragDropTargetId = id;
12918  return true;
12919 }
12920 
12922 {
12923  ImGuiContext& g = *GImGui;
12924  return g.DragDropActive && g.DragDropAcceptIdPrev != 0;
12925 }
12926 
12928 {
12929  ImGuiContext& g = *GImGui;
12930  ImGuiWindow* window = g.CurrentWindow;
12931  ImGuiPayload& payload = g.DragDropPayload;
12932  IM_ASSERT(g.DragDropActive); // Not called between BeginDragDropTarget() and EndDragDropTarget() ?
12933  IM_ASSERT(payload.DataFrameCount != -1); // Forgot to call EndDragDropTarget() ?
12934  if (type != NULL && !payload.IsDataType(type))
12935  return NULL;
12936 
12937  // Accept smallest drag target bounding box, this allows us to nest drag targets conveniently without ordering constraints.
12938  // NB: We currently accept NULL id as target. However, overlapping targets requires a unique ID to function!
12939  const bool was_accepted_previously = (g.DragDropAcceptIdPrev == g.DragDropTargetId);
12940  ImRect r = g.DragDropTargetRect;
12941  float r_surface = r.GetWidth() * r.GetHeight();
12942  if (r_surface < g.DragDropAcceptIdCurrRectSurface)
12943  {
12944  g.DragDropAcceptIdCurr = g.DragDropTargetId;
12945  g.DragDropAcceptIdCurrRectSurface = r_surface;
12946  }
12947 
12948  // Render default drop visuals
12949  payload.Preview = was_accepted_previously;
12950  flags |= (g.DragDropSourceFlags & ImGuiDragDropFlags_AcceptNoDrawDefaultRect); // Source can also inhibit the preview (useful for external sources that lives for 1 frame)
12952  {
12953  // FIXME-DRAG: Settle on a proper default visuals for drop target.
12954  r.Expand(3.5f);
12955  bool push_clip_rect = !window->ClipRect.Contains(r);
12956  if (push_clip_rect) window->DrawList->PushClipRectFullScreen();
12957  window->DrawList->AddRect(r.Min, r.Max, GetColorU32(ImGuiCol_DragDropTarget), 0.0f, ~0, 2.0f);
12958  if (push_clip_rect) window->DrawList->PopClipRect();
12959  }
12960 
12961  g.DragDropAcceptFrameCount = g.FrameCount;
12962  payload.Delivery = was_accepted_previously && !IsMouseDown(g.DragDropMouseButton); // For extern drag sources affecting os window focus, it's easier to just test !IsMouseDown() instead of IsMouseReleased()
12964  return NULL;
12965 
12966  return &payload;
12967 }
12968 
12969 // We don't really use/need this now, but added it for the sake of consistency and because we might need it later.
12971 {
12972  ImGuiContext& g = *GImGui; (void)g;
12973  IM_ASSERT(g.DragDropActive);
12974 }
12975 
12976 //-----------------------------------------------------------------------------
12977 // PLATFORM DEPENDENT HELPERS
12978 //-----------------------------------------------------------------------------
12979 
12980 #if defined(_WIN32) && !defined(_WINDOWS_) && (!defined(IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS) || !defined(IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS))
12981 #undef WIN32_LEAN_AND_MEAN
12982 #define WIN32_LEAN_AND_MEAN
12983 #ifndef __MINGW32__
12984 #include <Windows.h>
12985 #else
12986 #include <windows.h>
12987 #endif
12988 #endif
12989 
12990 // Win32 API clipboard implementation
12991 #if defined(_WIN32) && !defined(IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS)
12992 
12993 #ifdef _MSC_VER
12994 #pragma comment(lib, "user32")
12995 #endif
12996 
12997 static const char* GetClipboardTextFn_DefaultImpl(void*)
12998 {
12999  static ImVector<char> buf_local;
13000  buf_local.clear();
13001  if (!OpenClipboard(NULL))
13002  return NULL;
13003  HANDLE wbuf_handle = GetClipboardData(CF_UNICODETEXT);
13004  if (wbuf_handle == NULL)
13005  {
13006  CloseClipboard();
13007  return NULL;
13008  }
13009  if (ImWchar* wbuf_global = (ImWchar*)GlobalLock(wbuf_handle))
13010  {
13011  int buf_len = ImTextCountUtf8BytesFromStr(wbuf_global, NULL) + 1;
13012  buf_local.resize(buf_len);
13013  ImTextStrToUtf8(buf_local.Data, buf_len, wbuf_global, NULL);
13014  }
13015  GlobalUnlock(wbuf_handle);
13016  CloseClipboard();
13017  return buf_local.Data;
13018 }
13019 
13020 static void SetClipboardTextFn_DefaultImpl(void*, const char* text)
13021 {
13022  if (!OpenClipboard(NULL))
13023  return;
13024  const int wbuf_length = ImTextCountCharsFromUtf8(text, NULL) + 1;
13025  HGLOBAL wbuf_handle = GlobalAlloc(GMEM_MOVEABLE, (SIZE_T)wbuf_length * sizeof(ImWchar));
13026  if (wbuf_handle == NULL)
13027  {
13028  CloseClipboard();
13029  return;
13030  }
13031  ImWchar* wbuf_global = (ImWchar*)GlobalLock(wbuf_handle);
13032  ImTextStrFromUtf8(wbuf_global, wbuf_length, text, NULL);
13033  GlobalUnlock(wbuf_handle);
13034  EmptyClipboard();
13035  SetClipboardData(CF_UNICODETEXT, wbuf_handle);
13036  CloseClipboard();
13037 }
13038 
13039 #else
13040 
13041 // Local ImGui-only clipboard implementation, if user hasn't defined better clipboard handlers
13042 static const char* GetClipboardTextFn_DefaultImpl(void*)
13043 {
13044  ImGuiContext& g = *GImGui;
13045  return g.PrivateClipboard.empty() ? NULL : g.PrivateClipboard.begin();
13046 }
13047 
13048 // Local ImGui-only clipboard implementation, if user hasn't defined better clipboard handlers
13049 static void SetClipboardTextFn_DefaultImpl(void*, const char* text)
13050 {
13051  ImGuiContext& g = *GImGui;
13053  const char* text_end = text + strlen(text);
13054  g.PrivateClipboard.resize((int)(text_end - text) + 1);
13055  memcpy(&g.PrivateClipboard[0], text, (size_t)(text_end - text));
13056  g.PrivateClipboard[(int)(text_end - text)] = 0;
13057 }
13058 
13059 #endif
13060 
13061 // Win32 API IME support (for Asian languages, etc.)
13062 #if defined(_WIN32) && !defined(__GNUC__) && !defined(IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS)
13063 
13064 #include <imm.h>
13065 #ifdef _MSC_VER
13066 #pragma comment(lib, "imm32")
13067 #endif
13068 
13069 static void ImeSetInputScreenPosFn_DefaultImpl(int x, int y)
13070 {
13071  // Notify OS Input Method Editor of text input position
13072  if (HWND hwnd = (HWND)GImGui->IO.ImeWindowHandle)
13073  if (HIMC himc = ImmGetContext(hwnd))
13074  {
13075  COMPOSITIONFORM cf;
13076  cf.ptCurrentPos.x = x;
13077  cf.ptCurrentPos.y = y;
13078  cf.dwStyle = CFS_FORCE_POSITION;
13079  ImmSetCompositionWindow(himc, &cf);
13080  }
13081 }
13082 
13083 #else
13084 
13085 static void ImeSetInputScreenPosFn_DefaultImpl(int, int) {}
13086 
13087 #endif
13088 
13089 //-----------------------------------------------------------------------------
13090 // HELP
13091 //-----------------------------------------------------------------------------
13092 
13093 void ImGui::ShowMetricsWindow(bool* p_open)
13094 {
13095  if (ImGui::Begin("ImGui Metrics", p_open))
13096  {
13097  ImGui::Text("Dear ImGui %s", ImGui::GetVersion());
13098  ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate);
13099  ImGui::Text("%d vertices, %d indices (%d triangles)", ImGui::GetIO().MetricsRenderVertices, ImGui::GetIO().MetricsRenderIndices, ImGui::GetIO().MetricsRenderIndices / 3);
13100  ImGui::Text("%d allocations", (int)GImAllocatorActiveAllocationsCount);
13101  static bool show_clip_rects = true;
13102  ImGui::Checkbox("Show clipping rectangles when hovering draw commands", &show_clip_rects);
13103  ImGui::Separator();
13104 
13105  struct Funcs
13106  {
13107  static void NodeDrawList(ImGuiWindow* window, ImDrawList* draw_list, const char* label)
13108  {
13109  bool node_open = ImGui::TreeNode(draw_list, "%s: '%s' %d vtx, %d indices, %d cmds", label, draw_list->_OwnerName ? draw_list->_OwnerName : "", draw_list->VtxBuffer.Size, draw_list->IdxBuffer.Size, draw_list->CmdBuffer.Size);
13110  if (draw_list == ImGui::GetWindowDrawList())
13111  {
13112  ImGui::SameLine();
13113  ImGui::TextColored(ImColor(255,100,100), "CURRENTLY APPENDING"); // Can't display stats for active draw list! (we don't have the data double-buffered)
13114  if (node_open) ImGui::TreePop();
13115  return;
13116  }
13117 
13118  ImDrawList* overlay_draw_list = ImGui::GetOverlayDrawList(); // Render additional visuals into the top-most draw list
13119  if (window && ImGui::IsItemHovered())
13120  overlay_draw_list->AddRect(window->Pos, window->Pos + window->Size, IM_COL32(255, 255, 0, 255));
13121  if (!node_open)
13122  return;
13123 
13124  int elem_offset = 0;
13125  for (const ImDrawCmd* pcmd = draw_list->CmdBuffer.begin(); pcmd < draw_list->CmdBuffer.end(); elem_offset += pcmd->ElemCount, pcmd++)
13126  {
13127  if (pcmd->UserCallback == NULL && pcmd->ElemCount == 0)
13128  continue;
13129  if (pcmd->UserCallback)
13130  {
13131  ImGui::BulletText("Callback %p, user_data %p", pcmd->UserCallback, pcmd->UserCallbackData);
13132  continue;
13133  }
13134  ImDrawIdx* idx_buffer = (draw_list->IdxBuffer.Size > 0) ? draw_list->IdxBuffer.Data : NULL;
13135  bool pcmd_node_open = ImGui::TreeNode((void*)(pcmd - draw_list->CmdBuffer.begin()), "Draw %4d %s vtx, tex 0x%p, clip_rect (%4.0f,%4.0f)-(%4.0f,%4.0f)", pcmd->ElemCount, draw_list->IdxBuffer.Size > 0 ? "indexed" : "non-indexed", pcmd->TextureId, pcmd->ClipRect.x, pcmd->ClipRect.y, pcmd->ClipRect.z, pcmd->ClipRect.w);
13136  if (show_clip_rects && ImGui::IsItemHovered())
13137  {
13138  ImRect clip_rect = pcmd->ClipRect;
13139  ImRect vtxs_rect;
13140  for (int i = elem_offset; i < elem_offset + (int)pcmd->ElemCount; i++)
13141  vtxs_rect.Add(draw_list->VtxBuffer[idx_buffer ? idx_buffer[i] : i].pos);
13142  clip_rect.Floor(); overlay_draw_list->AddRect(clip_rect.Min, clip_rect.Max, IM_COL32(255,255,0,255));
13143  vtxs_rect.Floor(); overlay_draw_list->AddRect(vtxs_rect.Min, vtxs_rect.Max, IM_COL32(255,0,255,255));
13144  }
13145  if (!pcmd_node_open)
13146  continue;
13147 
13148  // Display individual triangles/vertices. Hover on to get the corresponding triangle highlighted.
13149  ImGuiListClipper clipper(pcmd->ElemCount/3); // Manually coarse clip our print out of individual vertices to save CPU, only items that may be visible.
13150  while (clipper.Step())
13151  for (int prim = clipper.DisplayStart, vtx_i = elem_offset + clipper.DisplayStart*3; prim < clipper.DisplayEnd; prim++)
13152  {
13153  char buf[300];
13154  char *buf_p = buf, *buf_end = buf + IM_ARRAYSIZE(buf);
13155  ImVec2 triangles_pos[3];
13156  for (int n = 0; n < 3; n++, vtx_i++)
13157  {
13158  ImDrawVert& v = draw_list->VtxBuffer[idx_buffer ? idx_buffer[vtx_i] : vtx_i];
13159  triangles_pos[n] = v.pos;
13160  buf_p += ImFormatString(buf_p, (int)(buf_end - buf_p), "%s %04d: pos (%8.2f,%8.2f), uv (%.6f,%.6f), col %08X\n", (n == 0) ? "vtx" : " ", vtx_i, v.pos.x, v.pos.y, v.uv.x, v.uv.y, v.col);
13161  }
13162  ImGui::Selectable(buf, false);
13163  if (ImGui::IsItemHovered())
13164  {
13165  ImDrawListFlags backup_flags = overlay_draw_list->Flags;
13166  overlay_draw_list->Flags &= ~ImDrawListFlags_AntiAliasedLines; // Disable AA on triangle outlines at is more readable for very large and thin triangles.
13167  overlay_draw_list->AddPolyline(triangles_pos, 3, IM_COL32(255,255,0,255), true, 1.0f);
13168  overlay_draw_list->Flags = backup_flags;
13169  }
13170  }
13171  ImGui::TreePop();
13172  }
13173  ImGui::TreePop();
13174  }
13175 
13176  static void NodeWindows(ImVector<ImGuiWindow*>& windows, const char* label)
13177  {
13178  if (!ImGui::TreeNode(label, "%s (%d)", label, windows.Size))
13179  return;
13180  for (int i = 0; i < windows.Size; i++)
13181  Funcs::NodeWindow(windows[i], "Window");
13182  ImGui::TreePop();
13183  }
13184 
13185  static void NodeWindow(ImGuiWindow* window, const char* label)
13186  {
13187  if (!ImGui::TreeNode(window, "%s '%s', %d @ 0x%p", label, window->Name, window->Active || window->WasActive, window))
13188  return;
13189  ImGuiWindowFlags flags = window->Flags;
13190  NodeDrawList(window, window->DrawList, "DrawList");
13191  ImGui::BulletText("Pos: (%.1f,%.1f), Size: (%.1f,%.1f), SizeContents (%.1f,%.1f)", window->Pos.x, window->Pos.y, window->Size.x, window->Size.y, window->SizeContents.x, window->SizeContents.y);
13192  ImGui::BulletText("Flags: 0x%08X (%s%s%s%s%s%s..)", flags,
13193  (flags & ImGuiWindowFlags_ChildWindow) ? "Child " : "", (flags & ImGuiWindowFlags_Tooltip) ? "Tooltip " : "", (flags & ImGuiWindowFlags_Popup) ? "Popup " : "",
13194  (flags & ImGuiWindowFlags_Modal) ? "Modal " : "", (flags & ImGuiWindowFlags_ChildMenu) ? "ChildMenu " : "", (flags & ImGuiWindowFlags_NoSavedSettings) ? "NoSavedSettings " : "");
13195  ImGui::BulletText("Scroll: (%.2f/%.2f,%.2f/%.2f)", window->Scroll.x, GetScrollMaxX(window), window->Scroll.y, GetScrollMaxY(window));
13196  ImGui::BulletText("Active: %d, WriteAccessed: %d", window->Active, window->WriteAccessed);
13197  ImGui::BulletText("NavLastIds: 0x%08X,0x%08X, NavLayerActiveMask: %X", window->NavLastIds[0], window->NavLastIds[1], window->DC.NavLayerActiveMask);
13198  ImGui::BulletText("NavLastChildNavWindow: %s", window->NavLastChildNavWindow ? window->NavLastChildNavWindow->Name : "NULL");
13199  if (window->NavRectRel[0].IsInverted())
13200  ImGui::BulletText("NavRectRel[0]: (%.1f,%.1f)(%.1f,%.1f)", window->NavRectRel[0].Min.x, window->NavRectRel[0].Min.y, window->NavRectRel[0].Max.x, window->NavRectRel[0].Max.y);
13201  else
13202  ImGui::BulletText("NavRectRel[0]: <None>");
13203  if (window->RootWindow != window) NodeWindow(window->RootWindow, "RootWindow");
13204  if (window->DC.ChildWindows.Size > 0) NodeWindows(window->DC.ChildWindows, "ChildWindows");
13205  ImGui::BulletText("Storage: %d bytes", window->StateStorage.Data.Size * (int)sizeof(ImGuiStorage::Pair));
13206  ImGui::TreePop();
13207  }
13208  };
13209 
13210  // Access private state, we are going to display the draw lists from last frame
13211  ImGuiContext& g = *GImGui;
13212  Funcs::NodeWindows(g.Windows, "Windows");
13213  if (ImGui::TreeNode("DrawList", "Active DrawLists (%d)", g.DrawDataBuilder.Layers[0].Size))
13214  {
13215  for (int i = 0; i < g.DrawDataBuilder.Layers[0].Size; i++)
13216  Funcs::NodeDrawList(NULL, g.DrawDataBuilder.Layers[0][i], "DrawList");
13217  ImGui::TreePop();
13218  }
13219  if (ImGui::TreeNode("Popups", "Open Popups Stack (%d)", g.OpenPopupStack.Size))
13220  {
13221  for (int i = 0; i < g.OpenPopupStack.Size; i++)
13222  {
13223  ImGuiWindow* window = g.OpenPopupStack[i].Window;
13224  ImGui::BulletText("PopupID: %08x, Window: '%s'%s%s", g.OpenPopupStack[i].PopupId, window ? window->Name : "NULL", window && (window->Flags & ImGuiWindowFlags_ChildWindow) ? " ChildWindow" : "", window && (window->Flags & ImGuiWindowFlags_ChildMenu) ? " ChildMenu" : "");
13225  }
13226  ImGui::TreePop();
13227  }
13228  if (ImGui::TreeNode("Internal state"))
13229  {
13230  const char* input_source_names[] = { "None", "Mouse", "Nav", "NavGamepad", "NavKeyboard" }; IM_ASSERT(IM_ARRAYSIZE(input_source_names) == ImGuiInputSource_Count_);
13231  ImGui::Text("HoveredWindow: '%s'", g.HoveredWindow ? g.HoveredWindow->Name : "NULL");
13232  ImGui::Text("HoveredRootWindow: '%s'", g.HoveredRootWindow ? g.HoveredRootWindow->Name : "NULL");
13233  ImGui::Text("HoveredId: 0x%08X/0x%08X (%.2f sec)", g.HoveredId, g.HoveredIdPreviousFrame, g.HoveredIdTimer); // Data is "in-flight" so depending on when the Metrics window is called we may see current frame information or not
13234  ImGui::Text("ActiveId: 0x%08X/0x%08X (%.2f sec), ActiveIdSource: %s", g.ActiveId, g.ActiveIdPreviousFrame, g.ActiveIdTimer, input_source_names[g.ActiveIdSource]);
13235  ImGui::Text("ActiveIdWindow: '%s'", g.ActiveIdWindow ? g.ActiveIdWindow->Name : "NULL");
13236  ImGui::Text("NavWindow: '%s'", g.NavWindow ? g.NavWindow->Name : "NULL");
13237  ImGui::Text("NavId: 0x%08X, NavLayer: %d", g.NavId, g.NavLayer);
13238  ImGui::Text("NavActive: %d, NavVisible: %d", g.IO.NavActive, g.IO.NavVisible);
13239  ImGui::Text("NavActivateId: 0x%08X, NavInputId: 0x%08X", g.NavActivateId, g.NavInputId);
13240  ImGui::Text("NavDisableHighlight: %d, NavDisableMouseHover: %d", g.NavDisableHighlight, g.NavDisableMouseHover);
13241  ImGui::Text("DragDrop: %d, SourceId = 0x%08X, Payload \"%s\" (%d bytes)", g.DragDropActive, g.DragDropPayload.SourceId, g.DragDropPayload.DataType, g.DragDropPayload.DataSize);
13242  ImGui::TreePop();
13243  }
13244  }
13245  ImGui::End();
13246 }
13247 
13248 //-----------------------------------------------------------------------------
13249 
13250 // Include imgui_user.inl at the end of imgui.cpp to access private data/functions that aren't exposed.
13251 // Prefer just including imgui_internal.h from your code rather than using this define. If a declaration is missing from imgui_internal.h add it or request it on the github.
13252 #ifdef IMGUI_INCLUDE_IMGUI_USER_INL
13253 #include "imgui_user.inl"
13254 #endif
13255 
13256 //-----------------------------------------------------------------------------
void * memmove(void *dst, const void *src, size_t n)
Definition: Memory.c:31
float NavInputs[ImGuiNavInput_COUNT]
Definition: ImGui.h:1023
~ImGuiWindow()
Definition: ImGui.cpp:1951
IMGUI_API void TreePush(const char *str_id)
Definition: ImGui.cpp:12638
const char * ImStristr(const char *haystack, const char *haystack_end, const char *needle, const char *needle_end)
Definition: ImGui.cpp:1026
char InputBuf[256]
Definition: ImGui.h:1202
ImGuiCol Col
Definition: _ImGui.h:354
IMGUI_API bool BeginPopupContextItem(const char *str_id=NULL, int mouse_button=1)
Definition: ImGui.cpp:5019
void * ImFileLoadToMemory(const char *filename, const char *file_open_mode, int *out_file_size, int padding_bytes)
Definition: ImGui.cpp:1431
static ImVector< ImGuiStorage::Pair >::iterator LowerBound(ImVector< ImGuiStorage::Pair > &data, ImGuiID key)
Definition: ImGui.cpp:1477
IMGUI_API void PushStyleVar(ImGuiStyleVar idx, float val)
Definition: ImGui.cpp:6605
static void UpdateManualResize(ImGuiWindow *window, const ImVec2 &size_auto_fit, int *border_held, int resize_grip_count, ImU32 resize_grip_col[4])
Definition: ImGui.cpp:5451
IMGUI_API void SetNextWindowSize(const ImVec2 &size, ImGuiCond cond=0)
Definition: ImGui.cpp:6953
ImRect MenuBarRect() const
Definition: _ImGui.h:999
const ImWchar * ImStrbolW(const ImWchar *buf_mid_line, const ImWchar *buf_begin)
Definition: ImGui.cpp:1019
IMGUI_API bool ColorPicker3(const char *label, float col[3], ImGuiColorEditFlags flags=0)
Definition: ImGui.cpp:11711
ImVec2 BackupCursorPos
Definition: _ImGui.h:371
#define IMGUI_PAYLOAD_TYPE_COLOR_4F
Definition: ImGui.h:686
IMGUI_API void Image(ImTextureID user_texture_id, const ImVec2 &size, const ImVec2 &uv0=ImVec2(0, 0), const ImVec2 &uv1=ImVec2(1, 1), const ImVec4 &tint_col=ImVec4(1, 1, 1, 1), const ImVec4 &border_col=ImVec4(0, 0, 0, 0))
Definition: ImGui.cpp:7744
IMGUI_API bool SliderBehavior(const ImRect &frame_bb, ImGuiID id, float *v, float v_min, float v_max, float power, int decimal_precision, ImGuiSliderFlags flags=0)
Definition: ImGui.cpp:8558
bool Active
Definition: _ImGui.h:930
IMGUI_API void TextColoredV(const ImVec4 &col, const char *fmt, va_list args) IM_FMTLIST(2)
Definition: ImGui.cpp:7269
const char *(* GetClipboardTextFn)(void *user_data)
Definition: ImGui.h:993
int FocusIdxTabRequestNext
Definition: _ImGui.h:982
static ImGuiWindow * NavRestoreLastChildNavWindow(ImGuiWindow *window)
Definition: ImGui.cpp:2300
int FocusIdxTabCounter
Definition: _ImGui.h:978
IMGUI_API bool IsWindowHovered(ImGuiHoveredFlags flags=0)
Definition: ImGui.cpp:6716
IMGUI_API float GetCursorPosX()
Definition: ImGui.cpp:7097
void PathStroke(ImU32 col, bool closed, float thickness=1.0f)
Definition: ImGui.h:1545
void(* WriteAllFn)(ImGuiContext *ctx, ImGuiSettingsHandler *handler, ImGuiTextBuffer *out_buf)
Definition: _ImGui.h:438
IMGUI_API float * GetFloatRef(ImGuiID key, float default_val=0.0f)
Definition: ImGui.cpp:1559
ImGuiWindow * RootWindowForTitleBarHighlight
Definition: _ImGui.h:967
IMGUI_API ImVec2 GetCursorStartPos()
Definition: ImGui.cpp:7130
static bool Items_ArrayGetter(void *data, int idx, const char **out_text)
Definition: ImGui.cpp:10716
static int InputTextCalcTextLenAndLineCount(const char *text_begin, const char **out_text_end)
Definition: ImGui.cpp:9541
IMGUI_API void SetTooltip(const char *fmt,...) IM_FMTARGS(1)
Definition: ImGui.cpp:4765
#define va_copy(dest, src)
Definition: ImGui.cpp:1727
int ImFormatStringV(char *buf, size_t buf_size, const char *fmt, va_list args)
Definition: ImGui.cpp:1078
IMGUI_API bool ArrowButton(ImGuiID id, ImGuiDir dir, ImVec2 padding, ImGuiButtonFlags flags=0)
Definition: ImGui.cpp:7719
IMGUI_API void RenderText(ImVec2 pos, const char *text, const char *text_end=NULL, bool hide_text_after_hash=true)
Definition: ImGui.cpp:4168
IMGUI_API bool IsMouseReleased(int button)
Definition: ImGui.cpp:4569
void * UserData
Definition: ImGui.h:973
IMGUI_API void SetNextTreeNodeOpen(bool is_open, ImGuiCond cond=0)
Definition: ImGui.cpp:8241
ImVec2 Scroll
Definition: _ImGui.h:925
float WindowBorderSize
Definition: _ImGui.h:922
ImDrawList ** CmdLists
Definition: ImGui.h:1581
ImRect WindowRectClipped
Definition: _ImGui.h:956
int ImGuiColorEditFlags
Definition: ImGui.h:94
#define STB_TEXTEDIT_K_BACKSPACE
Definition: ImGui.cpp:9681
#define STB_TEXTEDIT_GETWIDTH_NEWLINE
Definition: _ImGui.h:66
ImVec2 ImLineClosestPoint(const ImVec2 &a, const ImVec2 &b, const ImVec2 &p)
Definition: ImGui.cpp:928
IMGUI_API bool RadioButton(const char *label, bool active)
Definition: ImGui.cpp:9473
void * GetVarPtr(ImGuiStyle *style) const
Definition: ImGui.cpp:6570
int BeginCount
Definition: _ImGui.h:940
IMGUI_API void SetWindowCollapsed(bool collapsed, ImGuiCond cond=0)
Definition: ImGui.cpp:6904
IMGUI_API ImVec2 GetCursorPos()
Definition: ImGui.cpp:7091
float TextWrapPos
Definition: _ImGui.h:862
ImGuiPopupPositionPolicy
Definition: ImGui.cpp:5181
static float CalcMaxPopupHeightFromItemCount(int items_count)
Definition: ImGui.cpp:10562
static float GetColumnWidthEx(ImGuiColumnsSet *columns, int column_index, bool before_resize=false)
Definition: ImGui.cpp:12388
static void SetNavIDAndMoveMouse(ImGuiID id, int nav_layer, const ImRect &rect_rel)
Definition: ImGui.cpp:2012
ImGuiCond SetWindowPosAllowFlags
Definition: _ImGui.h:947
float FontSize
Definition: _ImGui.h:581
ImDrawIdx * _IdxWritePtr
Definition: ImGui.h:1501
IMGUI_API void SetScrollFromPosY(float pos_y, float center_y_ratio=0.5f)
Definition: ImGui.cpp:7183
void ImTriangleBarycentricCoords(const ImVec2 &a, const ImVec2 &b, const ImVec2 &c, const ImVec2 &p, float &out_u, float &out_v, float &out_w)
Definition: ImGui.cpp:949
static bool IsKeyPressedMap(ImGuiKey key, bool repeat=true)
Definition: ImGui.cpp:4475
static ImWchar STB_TEXTEDIT_NEWLINE
Definition: ImGui.cpp:9607
char * Name
Definition: _ImGui.h:909
bool ActiveIdIsJustActivated
Definition: _ImGui.h:605
const char * LogFilename
Definition: ImGui.h:966
#define STB_TEXTEDIT_K_WORDLEFT
Definition: ImGui.cpp:9684
IMGUI_API float GetFontSize()
Definition: ImGui.cpp:7071
IMGUI_API void AddCircle(const ImVec2 &centre, float radius, ImU32 col, int num_segments=12, float thickness=1.0f)
Definition: Draw.cpp:1069
IMGUI_API void AddRectFilledMultiColor(const ImVec2 &a, const ImVec2 &b, ImU32 col_upr_left, ImU32 col_upr_right, ImU32 col_bot_right, ImU32 col_bot_left)
Definition: Draw.cpp:1008
IMGUI_API void MarkIniSettingsDirty()
Definition: ImGui.cpp:3791
IMGUI_API void RenderCheckMark(ImVec2 pos, ImU32 col, float sz)
Definition: ImGui.cpp:4324
IMGUI_API bool ImageButton(ImTextureID user_texture_id, const ImVec2 &size, const ImVec2 &uv0=ImVec2(0, 0), const ImVec2 &uv1=ImVec2(1, 1), int frame_padding=-1, const ImVec4 &bg_col=ImVec4(0, 0, 0, 0), const ImVec4 &tint_col=ImVec4(1, 1, 1, 1))
Definition: ImGui.cpp:7772
IMGUI_API void SetVoidPtr(ImGuiID key, void *val)
Definition: ImGui.cpp:1603
ImGuiWindow * ParentWindow
Definition: _ImGui.h:965
IMGUI_API void PushColumnClipRect(int column_index=-1)
Definition: ImGui.cpp:12445
static int ImTextCharToUtf8(char *buf, int buf_size, unsigned int c)
Definition: ImGui.cpp:1234
#define IM_COL32_WHITE
Definition: ImGui.h:1356
IMGUI_API void PopTextureID()
Definition: Draw.cpp:459
IMGUI_API void ColorEditOptionsPopup(const float *col, ImGuiColorEditFlags flags)
Definition: ImGui.cpp:11423
IMGUI_API void ProgressBar(float fraction, const ImVec2 &size_arg=ImVec2(-1, 0), const char *overlay=NULL)
Definition: ImGui.cpp:9374
IMGUI_API float RoundScalar(float value, int decimal_precision)
Definition: ImGui.cpp:8515
static ImRect GetBorderRect(ImGuiWindow *window, int border_n, float perp_padding, float thickness)
Definition: ImGui.cpp:5438
IMGUI_API bool IsPopupOpen(ImGuiID id)
Definition: ImGui.cpp:4939
ImVec2 MousePos
Definition: ImGui.h:1012
IMGUI_API void AddInputCharacter(ImWchar c)
Definition: ImGui.cpp:901
IMGUI_API void SetColumnWidth(int column_index, float width)
Definition: ImGui.cpp:12434
int ImGuiColumnsFlags
Definition: ImGui.h:95
IMGUI_API void AlignTextToFramePadding()
Definition: ImGui.cpp:7421
ImVec2 GetTL() const
Definition: _ImGui.h:332
ImVector< ImWchar > Text
Definition: _ImGui.h:400
float GetWidth() const
Definition: _ImGui.h:330
static void SetWindowScrollX(ImGuiWindow *window, float new_scroll_x)
Definition: ImGui.cpp:6804
ImVec2 OpenPopupPos
Definition: _ImGui.h:452
ImDrawData DrawData
Definition: _ImGui.h:657
static ImFont * GetDefaultFont()
Definition: ImGui.cpp:6443
float MouseCursorScale
Definition: ImGui.h:943
IMGUI_API ImGuiStorage * GetStateStorage()
Definition: ImGui.cpp:7244
IMGUI_API void PopClipRect()
Definition: Draw.cpp:446
int ImStrnicmp(const char *str1, const char *str2, size_t count)
Definition: ImGui.cpp:983
void OnKeyPressed(int key)
Definition: ImGui.cpp:9693
ImRect ClipRect
Definition: _ImGui.h:955
void(* SetClipboardTextFn)(void *user_data, const char *text)
Definition: ImGui.h:994
unsigned short ImWchar
Definition: ImGui.h:84
IMGUI_API void DeleteChars(int pos, int bytes_count)
Definition: ImGui.cpp:9703
IMGUI_API void ClosePopupsOverWindow(ImGuiWindow *ref_window)
Definition: ImGui.cpp:4832
IMGUI_API bool InputTextMultiline(const char *label, char *buf, size_t buf_size, const ImVec2 &size=ImVec2(0, 0), ImGuiInputTextFlags flags=0, ImGuiTextEditCallback callback=NULL, void *user_data=NULL)
Definition: ImGui.cpp:10399
static void FocusFrontMostActiveWindow(ImGuiWindow *ignore_window)
Definition: ImGui.cpp:6389
IMGUI_API const char * FindRenderedTextEnd(const char *text, const char *text_end=NULL)
Definition: ImGui.cpp:4083
int ImGuiNavInput
Definition: ImGui.h:88
static void LogRenderedText(const ImVec2 *ref_pos, const char *text, const char *text_end=NULL)
Definition: ImGui.cpp:4116
int WantCaptureMouseNextFrame
Definition: _ImGui.h:710
float GetHeight() const
Definition: _ImGui.h:331
IMGUI_API ImGuiWindowSettings * FindWindowSettings(ImGuiID id)
Definition: ImGui.cpp:3665
static float Plot_ArrayGetter(void *data, int idx)
Definition: ImGui.cpp:9344
IMGUI_API bool IsWindowChildOf(ImGuiWindow *window, ImGuiWindow *potential_parent)
Definition: ImGui.cpp:6703
IMGUI_API void ChannelsSetCurrent(int channel_index)
Definition: Draw.cpp:533
#define IMGUI_PAYLOAD_TYPE_COLOR_3F
Definition: ImGui.h:685
IMGUI_API void PopItemFlag()
Definition: ImGui.cpp:6492
void PathFillConvex(ImU32 col)
Definition: ImGui.h:1544
IMGUI_API void appendf(const char *fmt,...) IM_FMTARGS(2)
Definition: ImGui.cpp:1752
int ImGuiDragDropFlags
Definition: ImGui.h:97
IMGUI_API bool OpenPopupOnItemClick(const char *str_id=NULL, int mouse_button=1)
Definition: ImGui.cpp:5003
IMGUI_API bool InputInt3(const char *label, int v[3], ImGuiInputTextFlags extra_flags=0)
Definition: ImGui.cpp:10552
IMGUI_API void SetCursorPos(const ImVec2 &local_pos)
Definition: ImGui.cpp:7109
IMGUI_API bool BeginCombo(const char *label, const char *preview_value, ImGuiComboFlags flags=0)
Definition: ImGui.cpp:10570
static float ImSaturate(float f)
Definition: _ImGui.h:150
ImGuiLayoutType LayoutType
Definition: _ImGui.h:856
IMGUI_API bool BeginPopupModal(const char *name, bool *p_open=NULL, ImGuiWindowFlags flags=0)
Definition: ImGui.cpp:4951
static bool is_separator(unsigned int c)
Definition: ImGui.cpp:9621
IMGUI_API void split(char separator, ImVector< TextRange > &out)
Definition: ImGui.cpp:1651
#define STB_TEXTEDIT_K_DELETE
Definition: ImGui.cpp:9680
void resize(int new_size)
Definition: ImGui.h:1142
static float GetDraggedColumnOffset(ImGuiColumnsSet *columns, int column_index)
Definition: ImGui.cpp:12346
IMGUI_API const ImGuiPayload * AcceptDragDropPayload(const char *type, ImGuiDragDropFlags flags=0)
Definition: ImGui.cpp:12927
float FontWindowScale
Definition: _ImGui.h:963
Definition: ImGui.h:117
IMGUI_API bool IsMouseClicked(int button, bool repeat=false)
Definition: ImGui.cpp:4551
static int ImTextCountUtf8BytesFromChar(unsigned int c)
Definition: ImGui.cpp:1271
IMGUI_API bool IsItemClicked(int mouse_button=0)
Definition: ImGui.cpp:4675
GLdouble GLdouble GLint stride
IMGUI_API bool IsKeyPressed(int user_key_index, bool repeat=true)
Definition: ImGui.cpp:4514
#define IM_ARRAYSIZE(_ARR)
Definition: ImGui.h:46
#define STB_TEXTEDIT_K_RIGHT
Definition: ImGui.cpp:9673
float CurveTessellationTol
Definition: ImGui.h:946
ImVec2 GetBL() const
Definition: _ImGui.h:334
IMGUI_API void * GetVoidPtr(ImGuiID key) const
Definition: ImGui.cpp:1537
IMGUI_API void PushMultiItemsWidths(int components, float width_full=0.0f)
Definition: ImGui.cpp:6408
IMGUI_API void RenderFrameBorder(ImVec2 p_min, ImVec2 p_max, float rounding=0.0f)
Definition: ImGui.cpp:4267
IMGUI_API void PopTextWrapPos()
Definition: ImGui.cpp:6526
float ChildBorderSize
Definition: ImGui.h:925
ImVec2 DisplaySize
Definition: ImGui.h:961
bool IsLoaded() const
Definition: ImGui.h:1767
ImGuiInputTextFlags Flags
Definition: ImGui.h:1285
static void SettingsHandlerWindow_WriteAll(ImGuiContext *imgui_ctx, ImGuiSettingsHandler *handler, ImGuiTextBuffer *buf)
Definition: ImGui.cpp:3555
static bool IsWindowContentHoverable(ImGuiWindow *window, ImGuiHoveredFlags flags)
Definition: ImGui.cpp:2093
IMGUI_API void CalcListClipping(int items_count, float items_height, int *out_items_display_start, int *out_items_display_end)
Definition: ImGui.cpp:4405
unsigned int ImGuiID
Definition: ImGui.h:83
IMGUI_API bool IsMouseDown(int button)
Definition: ImGui.cpp:4535
bool MouseClicked[5]
Definition: ImGui.h:1053
ImVector< ImFontGlyph > Glyphs
Definition: ImGui.h:1745
ImVec2 PosFloat
Definition: _ImGui.h:912
static float ImFloor(float f)
Definition: _ImGui.h:161
IMGUI_API void AddInputCharactersUTF8(const char *utf8_chars)
Definition: ImGui.cpp:911
bool NavHideHighlightOneFrame
Definition: _ImGui.h:846
int NavLayer
Definition: _ImGui.h:638
ImVec2 ItemSpacing
Definition: ImGui.h:931
IMGUI_API ImVec2 GetItemRectMin()
Definition: ImGui.cpp:4714
static void SetCurrentWindow(ImGuiWindow *window)
Definition: ImGui.cpp:1995
IMGUI_API bool IsItemActive()
Definition: ImGui.cpp:4658
IMGUI_API bool ColorPicker4(const char *label, float col[4], ImGuiColorEditFlags flags=0, const float *ref_col=NULL)
Definition: ImGui.cpp:11744
ImGuiID LastItemId
Definition: _ImGui.h:842
IMGUI_API void SetHoveredID(ImGuiID id)
Definition: ImGui.cpp:2072
ImGuiID HoveredId
Definition: _ImGui.h:597
static ImVec2 NavCalcPreferredMousePos()
Definition: ImGui.cpp:2699
static const ImGuiStyleVarInfo GStyleVarInfo[]
Definition: ImGui.cpp:6573
bool Valid
Definition: ImGui.h:1580
ImDrawList OverlayDrawList
Definition: _ImGui.h:660
int FocusIdxAllRequestCurrent
Definition: _ImGui.h:979
IMGUI_API void SetNextWindowFocus()
Definition: ImGui.cpp:6983
IMGUI_API ImVec2 GetMouseDragDelta(int button=0, float lock_threshold=-1.0f)
Definition: ImGui.cpp:4618
GLuint GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat t1
bool IsInverted() const
Definition: _ImGui.h:348
int NavLayerActiveMask
Definition: _ImGui.h:850
IMGUI_API void NewFrame()
Definition: ImGui.cpp:3260
ImGuiID NavLastIds[2]
Definition: _ImGui.h:972
IMGUI_API void AddPolyline(const ImVec2 *points, const int num_points, ImU32 col, bool closed, float thickness)
Definition: Draw.cpp:606
bool BackupActiveIdIsAlive
Definition: _ImGui.h:378
typedef void(APIENTRY *GLDEBUGPROC)(GLenum source
IMGUI_API void SetItemDefaultFocus()
Definition: ImGui.cpp:7221
static bool IsNavInputDown(ImGuiNavInput n)
Definition: ImGui.cpp:2752
IMGUI_API void EndTooltip()
Definition: ImGui.cpp:4778
IMGUI_API bool FocusableItemRegister(ImGuiWindow *window, ImGuiID id, bool tab_stop=true)
Definition: ImGui.cpp:2506
#define IM_ASSERT(_EXPR)
Definition: ImGui.h:34
IMGUI_API bool InputInt4(const char *label, int v[4], ImGuiInputTextFlags extra_flags=0)
Definition: ImGui.cpp:10557
static ImGuiWindow * FindWindowNavigable(int i_start, int i_stop, int dir)
Definition: ImGui.cpp:2720
IMGUI_API void LogButtons()
Definition: ImGui.cpp:7892
float CellMaxY
Definition: _ImGui.h:477
ImGuiWindow * RootWindowForNav
Definition: _ImGui.h:969
IMGUI_API void CaptureMouseFromApp(bool capture=true)
Definition: ImGui.cpp:4653
ImGuiID TypeHash
Definition: _ImGui.h:435
float BackupIndentX
Definition: _ImGui.h:373
static void UpdateMovingWindow()
Definition: ImGui.cpp:3221
static void * GImAllocatorUserData
Definition: ImGui.cpp:776
ImVec2 ItemInnerSpacing
Definition: ImGui.h:932
float Descent
Definition: ImGui.h:1756
IMGUI_API void SetScrollHere(float center_y_ratio=0.5f)
Definition: ImGui.cpp:7199
IMGUI_API void SetAllocatorFunctions(void *(*alloc_func)(size_t sz, void *user_data), void(*free_func)(void *ptr, void *user_data), void *user_data=NULL)
Definition: ImGui.cpp:2610
IMGUI_API void PopAllowKeyboardFocus()
Definition: ImGui.cpp:6504
IMGUI_API bool SmallButton(const char *label)
Definition: ImGui.cpp:7656
ImVector< ImGuiItemFlags > ItemFlagsStack
Definition: _ImGui.h:863
static ImWchar STB_TEXTEDIT_GETCHAR(const STB_TEXTEDIT_STRING *obj, int idx)
Definition: ImGui.cpp:9604
IMGUI_API bool IsMouseHoveringRect(const ImVec2 &r_min, const ImVec2 &r_max, bool clip=true)
Definition: ImGui.cpp:4460
ImGuiColumnsSet * ColumnsSet
Definition: _ImGui.h:872
IMGUI_API void SetFocusID(ImGuiID id, ImGuiWindow *window)
Definition: ImGui.cpp:2045
IMGUI_API void PushClipRect(const ImVec2 &clip_rect_min, const ImVec2 &clip_rect_max, bool intersect_with_current_clip_rect)
Definition: ImGui.cpp:3921
bool IsFirstFrame
Definition: _ImGui.h:470
IMGUI_API void BuildSortByKey()
Definition: ImGui.cpp:1500
IMGUI_API bool BeginPopup(const char *str_id, ImGuiWindowFlags flags=0)
Definition: ImGui.cpp:4928
IMGUI_API void PathArcToFast(const ImVec2 &centre, float radius, int a_min_of_12, int a_max_of_12)
Definition: Draw.cpp:866
IMGUI_API void ShowMetricsWindow(bool *p_open=NULL)
Definition: ImGui.cpp:13093
IMGUI_API bool Draw(const char *label="Filter (inc,-exc)", float width=0.0f)
Definition: ImGui.cpp:1639
ImGuiID MoveId
Definition: _ImGui.h:923
IMGUI_API bool IsDragDropPayloadBeingAccepted()
Definition: ImGui.cpp:12921
static void NavSaveLastChildNavWindow(ImGuiWindow *child_window)
Definition: ImGui.cpp:2290
int CmdListsCount
Definition: ImGui.h:1582
ImRect InnerRect
Definition: _ImGui.h:957
IMGUI_API void BeginTooltip()
Definition: ImGui.cpp:4773
IMGUI_API bool TreeNodeEx(const char *label, ImGuiTreeNodeFlags flags=0)
Definition: ImGui.cpp:8143
static int STB_TEXTEDIT_STRINGLEN(const STB_TEXTEDIT_STRING *obj)
Definition: ImGui.cpp:9603
int(* ImGuiTextEditCallback)(ImGuiTextEditCallbackData *data)
Definition: ImGui.h:105
IMGUI_API bool IsWindowAppearing()
Definition: ImGui.cpp:6915
IMGUI_API ImVec2 CalcTextSizeA(float size, float max_width, float wrap_width, const char *text_begin, const char *text_end=NULL, const char **remaining=NULL) const
Definition: Draw.cpp:2372
const ImGuiResizeGripDef resize_grip_def[4]
Definition: ImGui.cpp:5430
IMGUI_API bool ListBox(const char *label, int *current_item, const char *const items[], int items_count, int height_in_items=-1)
Definition: ImGui.cpp:10923
float KeysDownDuration[512]
Definition: ImGui.h:1061
ImVec2 DisplayVisibleMax
Definition: ImGui.h:981
IMGUI_API void PushTextureID(ImTextureID texture_id)
Definition: Draw.cpp:453
IMGUI_API void SetNextWindowSizeConstraints(const ImVec2 &size_min, const ImVec2 &size_max, ImGuiSizeCallback custom_callback=NULL, void *custom_callback_data=NULL)
Definition: ImGui.cpp:6960
IMGUI_API void * MemAlloc(size_t size)
Definition: ImGui.cpp:2566
void swap(ImVector< T > &rhs)
Definition: ImGui.h:1138
int BeginOrderWithinContext
Definition: _ImGui.h:939
int ImGuiLayoutType
Definition: _ImGui.h:44
static bool NavMoveRequestButNoResultYet()
Definition: ImGui.cpp:2323
IMGUI_API bool * GetBoolRef(ImGuiID key, bool default_val=false)
Definition: ImGui.cpp:1554
int StackSizesBackup[6]
Definition: _ImGui.h:867
IMGUI_API void Indent(float indent_w=0.0f)
Definition: ImGui.cpp:12622
const ImFontGlyph * FallbackGlyph
Definition: ImGui.h:1748
float GetCharAdvance(ImWchar c) const
Definition: ImGui.h:1766
float LogLinePosY
Definition: _ImGui.h:839
IMGUI_API bool IsWindowFocused(ImGuiFocusedFlags flags=0)
Definition: ImGui.cpp:6757
IMGUI_API void AddTriangleFilled(const ImVec2 &a, const ImVec2 &b, const ImVec2 &c, ImU32 col)
Definition: Draw.cpp:1058
float BackupCurrentLineTextBaseOffset
Definition: _ImGui.h:376
IMGUI_API void PushTextWrapPos(float wrap_pos_x=0.0f)
Definition: ImGui.cpp:6519
ImVec2 SetWindowPosVal
Definition: _ImGui.h:950
IMGUI_API void PushButtonRepeat(bool repeat)
Definition: ImGui.cpp:6509
ImRect TitleBarRect() const
Definition: _ImGui.h:997
ImGuiStorage StateStorage
Definition: _ImGui.h:961
bool IsDataType(const char *type) const
Definition: ImGui.h:1336
bool MenuBarAppending
Definition: _ImGui.h:852
IMGUI_API void ResetMouseDragDelta(int button=0)
Definition: ImGui.cpp:4630
#define STB_TEXTEDIT_K_WORDRIGHT
Definition: ImGui.cpp:9685
IMGUI_API float GetFloat(ImGuiID key, float default_val=0.0f) const
Definition: ImGui.cpp:1529
IMGUI_API ImVec2 GetNavInputAmount2d(ImGuiNavDirSourceFlags dir_sources, ImGuiInputReadMode mode, float slow_factor=0.0f, float fast_factor=0.0f)
Definition: ImGui.cpp:2768
IMGUI_API void AddRect(const ImVec2 &a, const ImVec2 &b, ImU32 col, float rounding=0.0f, int rounding_corners_flags=ImDrawCornerFlags_All, float thickness=1.0f)
Definition: Draw.cpp:981
IMGUI_API void SetCurrentFont(ImFont *font)
Definition: ImGui.cpp:6449
bool MouseDoubleClicked[5]
Definition: ImGui.h:1054
IMGUI_API void BulletTextV(const char *fmt, va_list args) IM_FMTLIST(1)
Definition: ImGui.cpp:8319
ImGuiItemFlags ItemFlags
Definition: _ImGui.h:860
ImVec2 DisplayVisibleMin
Definition: ImGui.h:980
ImVec2 Size
Definition: _ImGui.h:914
IMGUI_API ImGuiMouseCursor GetMouseCursor()
Definition: ImGui.cpp:4638
static ImRect GetViewportRect()
Definition: ImGui.cpp:4732
IMGUI_API float GetColumnOffset(int column_index=-1)
Definition: ImGui.cpp:12363
int ImGuiStyleVar
Definition: ImGui.h:90
static void SetWindowConditionAllowFlags(ImGuiWindow *window, ImGuiCond flags, bool enabled)
Definition: ImGui.cpp:5247
float CalcFontSize() const
Definition: _ImGui.h:995
GLdouble GLdouble GLint GLint GLdouble v1
ImGuiMenuColumns MenuColumns
Definition: _ImGui.h:960
float WindowRounding
Definition: _ImGui.h:921
void * ImTextureID
Definition: ImGui.h:75
IMGUI_API bool TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char *label, const char *label_end=NULL)
Definition: ImGui.cpp:7963
IMGUI_API void SetStateStorage(ImGuiStorage *tree)
Definition: ImGui.cpp:7238
IMGUI_API void AddLine(const ImVec2 &a, const ImVec2 &b, ImU32 col, float thickness=1.0f)
Definition: Draw.cpp:971
IMGUI_API bool PassFilter(const char *text, const char *text_end=NULL) const
Definition: ImGui.cpp:1686
static void AddDrawListToDrawData(ImVector< ImDrawList *> *out_list, ImDrawList *draw_list)
Definition: ImGui.cpp:3835
#define IM_COL32_BLACK_TRANS
Definition: ImGui.h:1358
IMGUI_API void PushClipRect(ImVec2 clip_rect_min, ImVec2 clip_rect_max, bool intersect_with_current_clip_rect=false)
Definition: Draw.cpp:423
float FrameRounding
Definition: ImGui.h:929
GLdouble GLdouble GLdouble w
float CursorAnim
Definition: _ImGui.h:407
float NavInputsDownDuration[ImGuiNavInput_COUNT]
Definition: ImGui.h:1063
bool SkipItems
Definition: _ImGui.h:935
IMGUI_API bool InputText(const char *label, char *buf, size_t buf_size, ImGuiInputTextFlags flags=0, ImGuiTextEditCallback callback=NULL, void *user_data=NULL)
Definition: ImGui.cpp:10393
IMGUI_API void DestroyContext(ImGuiContext *ctx=NULL)
Definition: ImGui.cpp:2626
IMGUI_API bool TreeNodeV(const char *str_id, const char *fmt, va_list args) IM_FMTLIST(2)
Definition: ImGui.cpp:8174
ImVec2 GetCenter() const
Definition: _ImGui.h:328
IMGUI_API bool IsItemHovered(ImGuiHoveredFlags flags=0)
Definition: ImGui.cpp:2433
IMGUI_API ImVec2 GetItemRectSize()
Definition: ImGui.cpp:4726
static bool NavScoreItem(ImGuiNavMoveResult *result, ImRect cand)
Definition: ImGui.cpp:2162
IMGUI_API float GetWindowWidth()
Definition: ImGui.cpp:6785
IMGUI_API void RenderTriangle(ImVec2 pos, ImGuiDir dir, float scale=1.0f)
Definition: ImGui.cpp:4280
IMGUI_API void ** GetVoidPtrRef(ImGuiID key, void *default_val=NULL)
Definition: ImGui.cpp:1567
IMGUI_API bool IsAnyItemFocused()
Definition: ImGui.cpp:4692
float CurrentLineHeight
Definition: _ImGui.h:835
bool NavHasScroll
Definition: _ImGui.h:847
ImGuiColorEditFlags ColorEditOptions
Definition: _ImGui.h:681
IMGUI_API void Build()
Definition: ImGui.cpp:1669
GLenum GLenum GLsizei void GLsizei void * column
float CellMinY
Definition: _ImGui.h:477
IMGUI_API void ClosePopup(ImGuiID id)
Definition: ImGui.cpp:4886
IMGUI_API bool TreeNode(const char *label)
Definition: ImGui.cpp:8220
IMGUI_API float GetNavInputAmount(ImGuiNavInput n, ImGuiInputReadMode mode)
Definition: ImGui.cpp:2729
IMGUI_API ImVec2 GetContentRegionMax()
Definition: ImGui.cpp:6997
static void * SettingsHandlerWindow_ReadOpen(ImGuiContext *, ImGuiSettingsHandler *, const char *name)
Definition: ImGui.cpp:3537
bool OptCursorBlink
Definition: ImGui.h:985
T * Data
Definition: ImGui.h:1113
static void ImeSetInputScreenPosFn_DefaultImpl(int x, int y)
Definition: ImGui.cpp:13085
static void AddWindowToDrawData(ImVector< ImDrawList *> *out_list, ImGuiWindow *window)
Definition: ImGui.cpp:3868
ImVector< Pair > Data
Definition: ImGui.h:1250
int KeyMap[ImGuiKey_COUNT]
Definition: ImGui.h:970
IMGUI_API bool CheckboxFlags(const char *label, unsigned int *flags, unsigned int flags_value)
Definition: ImGui.cpp:9458
iterator begin()
Definition: ImGui.h:1130
IMGUI_API bool BeginChildFrame(ImGuiID id, const ImVec2 &size, ImGuiWindowFlags flags=0)
Definition: ImGui.cpp:5148
void(* ImeSetInputScreenPosFn)(int x, int y)
Definition: ImGui.h:999
IMGUI_API bool ColorEdit4(const char *label, float col[4], ImGuiColorEditFlags flags=0)
Definition: ImGui.cpp:11512
IMGUI_API void ActivateItem(ImGuiID id)
Definition: ImGui.cpp:7207
IMGUI_API void SetWindowPos(const ImVec2 &pos, ImGuiCond cond=0)
Definition: ImGui.cpp:6834
static ImGuiWindow * GetFrontMostModalRootWindow()
Definition: ImGui.cpp:4864
IMGUI_API bool DragBehavior(const ImRect &frame_bb, ImGuiID id, float *v, float v_speed, float v_min, float v_max, int decimal_precision, float power)
Definition: ImGui.cpp:8932
IMGUI_API bool BeginMenuBar()
Definition: ImGui.cpp:11043
IMGUI_API ImGuiTextFilter(const char *default_filter="")
Definition: ImGui.cpp:1625
float ColumnsMinSpacing
Definition: ImGui.h:935
ImVec2 Pos
Definition: _ImGui.h:913
float DeltaTime
Definition: ImGui.h:962
GLfloat GLfloat GLfloat alpha
GLdouble GLdouble GLdouble q
bool DragDropActive
Definition: _ImGui.h:664
IMGUI_API void PlotHistogram(const char *label, const float *values, int values_count, int values_offset=0, const char *overlay_text=NULL, float scale_min=FLT_MAX, float scale_max=FLT_MAX, ImVec2 graph_size=ImVec2(0, 0), int stride=sizeof(float))
Definition: ImGui.cpp:9362
IMGUI_API void MemFree(void *ptr)
Definition: ImGui.cpp:2572
ImGuiWindow * RootWindowForTabbing
Definition: _ImGui.h:968
IMGUI_API void Clear()
Definition: Draw.cpp:312
IMGUI_API void TextWrappedV(const char *fmt, va_list args) IM_FMTLIST(1)
Definition: ImGui.cpp:7299
IMGUI_API bool IsMousePosValid(const ImVec2 *mouse_pos=NULL)
Definition: ImGui.cpp:4609
int ImGuiInputTextFlags
Definition: ImGui.h:101
IMGUI_API void FlattenIntoSingleLayer()
Definition: ImGui.cpp:3889
IMGUI_API bool SplitterBehavior(ImGuiID id, const ImRect &bb, ImGuiAxis axis, float *size1, float *size2, float min_size1, float min_size2, float hover_extend=0.0f)
Definition: ImGui.cpp:12103
#define STB_TEXTEDIT_K_UP
Definition: ImGui.cpp:9674
IMGUI_API ImVec2 GetMousePos()
Definition: ImGui.cpp:4594
IMGUI_API bool BeginDragDropTargetCustom(const ImRect &bb, ImGuiID id)
Definition: ImGui.cpp:12875
IMGUI_API void Bullet()
Definition: ImGui.cpp:8296
int ImGuiHoveredFlags
Definition: ImGui.h:100
ImVec2 TexUvWhitePixel
Definition: _ImGui.h:499
ImDrawList * DrawList
Definition: _ImGui.h:964
static void DataTypeApplyOp(ImGuiDataType data_type, int op, void *value1, const void *value2)
Definition: ImGui.cpp:8377
ImVec2 SetWindowPosPivot
Definition: _ImGui.h:951
ImGuiDrawContext DC
Definition: _ImGui.h:953
static void RenderArrow(ImDrawList *draw_list, ImVec2 pos, ImVec2 half_sz, ImGuiDir direction, ImU32 col)
Definition: ImGui.cpp:11721
int ImGuiNavHighlightFlags
Definition: _ImGui.h:50
IMGUI_API ImGuiID GetHoveredID()
Definition: ImGui.cpp:2080
IMGUI_API bool InputFloat3(const char *label, float v[3], int decimal_precision=-1, ImGuiInputTextFlags extra_flags=0)
Definition: ImGui.cpp:10510
ImGuiWindow(ImGuiContext *context, const char *name)
Definition: ImGui.cpp:1892
void * memcpy(void *dst, const void *src, size_t n)
Definition: Memory.c:21
static int ImLerp(int a, int b, float t)
Definition: _ImGui.h:153
GLdouble GLdouble GLint GLint GLdouble GLdouble GLint GLint GLdouble GLdouble w2
static float GetScrollMaxX(ImGuiWindow *window)
Definition: ImGui.cpp:5372
ImGuiDataType Type
Definition: ImGui.cpp:6568
IMGUI_API void EndDragDropSource()
Definition: ImGui.cpp:12814
ImGuiID GetIDNoKeepAlive(const char *str, const char *str_end=NULL)
Definition: ImGui.cpp:1975
ImGuiID ActiveId
Definition: _ImGui.h:601
IMGUI_API void SameLine(float pos_x=0.0f, float spacing_w=-1.0f)
Definition: ImGui.cpp:12249
void pop_back()
Definition: ImGui.h:1158
static void ImSwap(int &a, int &b)
Definition: _ImGui.h:151
IMGUI_API void EndDragDropTarget()
Definition: ImGui.cpp:12970
IMGUI_API void SetMouseCursor(ImGuiMouseCursor type)
Definition: ImGui.cpp:4643
IMGUI_API bool SliderFloat2(const char *label, float v[2], float v_min, float v_max, const char *display_format="%.3f", float power=1.0f)
Definition: ImGui.cpp:8875
IMGUI_API ImVec2 GetContentRegionAvail()
Definition: ImGui.cpp:7006
int Size
Definition: ImGui.h:1111
ImGuiID GetIDFromRectangle(const ImRect &r_abs)
Definition: ImGui.cpp:1982
bool Collapsed
Definition: _ImGui.h:933
#define STB_TEXTEDIT_K_TEXTSTART
Definition: ImGui.cpp:9678
IMGUI_API void CaptureKeyboardFromApp(bool capture=true)
Definition: ImGui.cpp:4648
IMGUI_API void RenderRectFilledRangeH(ImDrawList *draw_list, const ImRect &rect, ImU32 col, float x_start_norm, float x_end_norm, float rounding)
Definition: Draw.cpp:2665
#define IMGUI_VERSION
Definition: ImGui.h:24
float Pos[4]
Definition: _ImGui.h:388
int ImGuiCond
Definition: ImGui.h:86
static void NavProcessItem(ImGuiWindow *window, const ImRect &nav_bb, const ImGuiID id)
Definition: ImGui.cpp:2337
float CurrentLineTextBaseOffset
Definition: _ImGui.h:836
IMGUI_API void SetFloat(ImGuiID key, float val)
Definition: ImGui.cpp:1592
ImGuiInputTextFlags EventFlag
Definition: ImGui.h:1284
static float PixelsToOffsetNorm(const ImGuiColumnsSet *columns, float offset)
Definition: ImGui.cpp:12339
ImVec2 DisplayOffset
Definition: ImGui.h:1744
IMGUI_API float GetScrollMaxY()
Definition: ImGui.cpp:7164
IMGUI_API void SetCurrentContext(ImGuiContext *ctx)
Definition: ImGui.cpp:2601
#define STB_TEXTEDIT_K_LEFT
Definition: ImGui.cpp:9672
static float ImLengthSqr(const ImVec2 &lhs)
Definition: _ImGui.h:158
ImFontAtlas * ContainerAtlas
Definition: ImGui.h:1755
IMGUI_API ImDrawList * GetWindowDrawList()
Definition: ImGui.cpp:7060
ImGuiWindow * NavLastChildNavWindow
Definition: _ImGui.h:971
ImVector< ImGuiWindow * > Windows
Definition: _ImGui.h:589
IMGUI_API bool Begin(const char *name, bool *p_open=NULL, ImGuiWindowFlags flags=0)
Definition: ImGui.cpp:5563
IMGUI_API bool InputInt2(const char *label, int v[2], ImGuiInputTextFlags extra_flags=0)
Definition: ImGui.cpp:10547
IMGUI_API bool IsKeyDown(int user_key_index)
Definition: ImGui.cpp:4488
IMGUI_API void PopStyleVar(int count=1)
Definition: ImGui.cpp:6633
int DataFrameCount
Definition: ImGui.h:1329
IMGUI_API void SetScrollY(float scroll_y)
Definition: ImGui.cpp:7176
float FontSize
Definition: ImGui.h:1742
int NavLayerCurrentMask
Definition: _ImGui.h:849
ImVec2 GetSize() const
Definition: _ImGui.h:329
void IM_DELETE(T *&p)
Definition: _ImGui.h:175
ImVec2 SizeContentsExplicit
Definition: _ImGui.h:918
ImGuiPlotType
Definition: _ImGui.h:250
ImGuiNavForward NavMoveRequestForward
Definition: _ImGui.h:651
float Alpha
Definition: ImGui.h:918
IMGUI_API void SetTooltipV(const char *fmt, va_list args) IM_FMTLIST(1)
Definition: ImGui.cpp:4758
ImGuiID GetID(const char *str, const char *str_end=NULL)
Definition: ImGui.cpp:1959
IMGUI_API ImVec2 CalcTextSize(const char *text, const char *text_end=NULL, bool hide_text_after_double_hash=false, float wrap_width=-1.0f)
Definition: ImGui.cpp:4376
IMGUI_API bool CollapsingHeader(const char *label, ImGuiTreeNodeFlags flags=0)
Definition: ImGui.cpp:8109
ImGuiStb::STB_TexteditState StbState
Definition: _ImGui.h:406
IMGUI_API ImVec2 GetWindowContentRegionMin()
Definition: ImGui.cpp:7018
IMGUI_API void AddTriangle(const ImVec2 &a, const ImVec2 &b, const ImVec2 &c, ImU32 col, float thickness=1.0f)
Definition: Draw.cpp:1047
IMGUI_API bool BeginPopupContextWindow(const char *str_id=NULL, int mouse_button=1, bool also_over_items=true)
Definition: ImGui.cpp:5029
static int ImClamp(int v, int mn, int mx)
Definition: _ImGui.h:147
IMGUI_API bool ListBoxHeader(const char *label, const ImVec2 &size=ImVec2(0, 0))
Definition: ImGui.cpp:10866
IMGUI_API void Dummy(const ImVec2 &size)
Definition: ImGui.cpp:12158
static ImVec2 CalcSizeAfterConstraint(ImGuiWindow *window, ImVec2 new_size)
Definition: ImGui.cpp:5310
IMGUI_API void KeepAliveID(ImGuiID id)
Definition: ImGui.cpp:2086
void Expand(const float amount)
Definition: _ImGui.h:341
IMGUI_API void BulletText(const char *fmt,...) IM_FMTARGS(1)
Definition: ImGui.cpp:8343
static void NavUpdateAnyRequestFlag()
Definition: ImGui.cpp:2317
static int ImMax(int lhs, int rhs)
Definition: _ImGui.h:142
float PrevLineHeight
Definition: _ImGui.h:837
static void MarkIniSettingsDirty(ImGuiWindow *window)
Definition: ImGui.cpp:3798
IMGUI_API bool IsAnyItemHovered()
Definition: ImGui.cpp:4680
#define IM_NEW(_TYPE)
Definition: _ImGui.h:174
static bool STB_TEXTEDIT_INSERTCHARS(STB_TEXTEDIT_STRING *obj, int pos, const ImWchar *new_text, int new_text_len)
Definition: ImGui.cpp:9648
ImVector< char > TempTextBuffer
Definition: _ImGui.h:402
float ColumnsOffsetX
Definition: _ImGui.h:871
ImRect LastItemRect
Definition: _ImGui.h:844
int BackupInt[2]
Definition: _ImGui.h:362
#define IM_OFFSETOF(_TYPE, _MEMBER)
Definition: ImGui.h:47
GLenum GLuint GLenum GLsizei const GLchar * buf
ImGuiID OpenParentId
Definition: _ImGui.h:451
float w
Definition: ImGui.h:130
void SelectAll()
Definition: _ImGui.h:416
static void *(* GImAllocatorAllocFunc)(size_t size, void *user_data)
Definition: ImGui.cpp:774
IMGUI_API const char * GetStyleColorName(ImGuiCol idx)
Definition: ImGui.cpp:6648
bool WriteAccessed
Definition: _ImGui.h:932
IMGUI_API bool IsMouseDragging(int button=0, float lock_threshold=-1.0f)
Definition: ImGui.cpp:4583
int ImFormatString(char *buf, size_t buf_size, const char *fmt,...)
Definition: ImGui.cpp:1064
#define IMGUI_DEBUG_NAV_SCORING
Definition: ImGui.cpp:647
static const ImGuiStyleVarInfo * GetStyleVarInfo(ImGuiStyleVar idx)
Definition: ImGui.cpp:6598
IMGUI_API bool BeginChild(const char *str_id, const ImVec2 &size=ImVec2(0, 0), bool border=false, ImGuiWindowFlags flags=0)
Definition: ImGui.cpp:5095
int DisplayStart
Definition: ImGui.h:1398
GLenum GLenum GLsizei const GLuint GLboolean enabled
IMGUI_API ImVec2 GetWindowContentRegionMax()
Definition: ImGui.cpp:7024
IMGUI_API int GetInt(ImGuiID key, int default_val=0) const
Definition: ImGui.cpp:1516
IMGUI_API bool IsRectVisible(const ImVec2 &size)
Definition: ImGui.cpp:12169
IMGUI_API bool SliderIntN(const char *label, int *v, int components, int v_min, int v_max, const char *display_format)
Definition: ImGui.cpp:8890
ImGuiColumnsFlags Flags
Definition: _ImGui.h:469
IMGUI_API bool Step()
Definition: ImGui.cpp:1851
void ClipWith(const ImRect &r)
Definition: _ImGui.h:344
static float STB_TEXTEDIT_GETWIDTH(STB_TEXTEDIT_STRING *obj, int line_start_idx, int char_idx)
Definition: ImGui.cpp:9605
ImVec2 SizeFullAtLastBegin
Definition: _ImGui.h:916
ImVec2 WindowMinSize
Definition: ImGui.h:922
GLdouble GLdouble GLint GLint GLdouble GLdouble GLint GLint GLdouble w1
ImGuiTextEditState InputTextState
Definition: _ImGui.h:678
IMGUI_API void ColorTooltip(const char *text, const float *col, ImGuiColorEditFlags flags)
Definition: ImGui.cpp:11259
IMGUI_API void TextUnformatted(const char *text, const char *text_end=NULL)
Definition: ImGui.cpp:7315
bool CollapseToggleWanted
Definition: _ImGui.h:934
bool Preview
Definition: ImGui.h:1331
IMGUI_API void TreePushRawID(ImGuiID id)
Definition: ImGui.cpp:12654
IMGUI_API bool DragFloat4(const char *label, float v[4], float v_speed=1.0f, float v_min=0.0f, float v_max=0.0f, const char *display_format="%.3f", float power=1.0f)
Definition: ImGui.cpp:9118
static int FindWindowIndex(ImGuiWindow *window)
Definition: ImGui.cpp:2711
IMGUI_API void PushItemFlag(ImGuiItemFlags option, bool enabled)
Definition: ImGui.cpp:6482
ImGuiWindow * RootWindow
Definition: _ImGui.h:966
static void NavScrollToBringItemIntoView(ImGuiWindow *window, ImRect &item_rect_rel)
Definition: ImGui.cpp:2916
FILE * ImFileOpen(const char *filename, const char *mode)
Definition: ImGui.cpp:1413
float MouseDownDuration[5]
Definition: ImGui.h:1057
static const char * GetClipboardTextFn_DefaultImpl(void *user_data)
Definition: ImGui.cpp:13042
IMGUI_API void Scrollbar(ImGuiLayoutType direction)
Definition: ImGui.cpp:6221
IMGUI_API void SetColumnOffset(int column_index, float offset_x)
Definition: ImGui.cpp:12412
ImVec2 Max
Definition: _ImGui.h:321
IMGUI_API void Unindent(float indent_w=0.0f)
Definition: ImGui.cpp:12630
const char * _OwnerName
Definition: ImGui.h:1498
static void FreeWrapper(void *ptr, void *user_data)
Definition: ImGui.cpp:768
IMGUI_API int GetColumnsCount()
Definition: ImGui.cpp:12328
IMGUI_API bool InputIntN(const char *label, int *v, int components, ImGuiInputTextFlags extra_flags)
Definition: ImGui.cpp:10520
const float * Values
Definition: ImGui.cpp:9338
IMGUI_API bool SliderAngle(const char *label, float *v_rad, float v_degrees_min=-360.0f, float v_degrees_max=+360.0f)
Definition: ImGui.cpp:8819
float ItemWidthDefault
Definition: _ImGui.h:959
IMGUI_API void FocusWindow(ImGuiWindow *window)
Definition: ImGui.cpp:6356
ImVector< ImDrawCmd > CmdBuffer
Definition: ImGui.h:1491
IMGUI_API bool ColorEdit3(const char *label, float col[3], ImGuiColorEditFlags flags=0)
Definition: ImGui.cpp:11418
bool AutoFitOnlyGrows
Definition: _ImGui.h:943
float ChildRounding
Definition: ImGui.h:924
IMGUI_API void RenderNavHighlight(const ImRect &bb, ImGuiID id, ImGuiNavHighlightFlags flags=ImGuiNavHighlightFlags_TypeDefault)
Definition: ImGui.cpp:4342
IMGUI_API void AddText(const ImVec2 &pos, ImU32 col, const char *text_begin, const char *text_end=NULL)
Definition: Draw.cpp:1128
ImGuiDir AutoPosLastDirection
Definition: _ImGui.h:945
void * ClipboardUserData
Definition: ImGui.h:995
ImRect ContentsRegionRect
Definition: _ImGui.h:919
ImDrawListSharedData DrawListSharedData
Definition: _ImGui.h:583
IMGUI_API bool SliderFloat3(const char *label, float v[3], float v_min, float v_max, const char *display_format="%.3f", float power=1.0f)
Definition: ImGui.cpp:8880
IMGUI_API ImVec2 GetMousePosOnOpeningCurrentPopup()
Definition: ImGui.cpp:4600
IMGUI_API bool ItemAdd(const ImRect &bb, ImGuiID id, const ImRect *nav_bb=NULL)
Definition: ImGui.cpp:2395
float MouseDoubleClickTime
Definition: ImGui.h:967
float GrabMinSize
Definition: ImGui.h:938
static float NavScoreItemDistInterval(float a0, float a1, float b0, float b1)
Definition: ImGui.cpp:2152
int ImGuiItemFlags
Definition: _ImGui.h:48
ImGuiID SourceId
Definition: ImGui.h:1327
float KeysDownDurationPrev[512]
Definition: ImGui.h:1062
IMGUI_API ImGuiIO & GetIO()
Definition: ImGui.cpp:2636
#define IM_COL32_A_MASK
Definition: ImGui.h:1353
void Translate(const ImVec2 &v)
Definition: _ImGui.h:343
bool ScrollbarX
Definition: _ImGui.h:928
ImVector< ImGuiColumnData > Columns
Definition: _ImGui.h:478
IMGUI_API bool InputScalarAsWidgetReplacement(const ImRect &aabb, const char *label, ImGuiDataType data_type, void *data_ptr, ImGuiID id, int decimal_precision)
Definition: ImGui.cpp:8460
int ImGuiComboFlags
Definition: ImGui.h:98
void CursorClamp()
Definition: _ImGui.h:413
ImVec2 SizeFull
Definition: _ImGui.h:915
void CursorAnimReset()
Definition: _ImGui.h:412
unsigned int ImU32
Definition: ImGui.h:82
int ImTextCharFromUtf8(unsigned int *out_char, const char *in_text, const char *in_text_end)
Definition: ImGui.cpp:1141
IMGUI_API bool DragInt4(const char *label, int v[4], float v_speed=1.0f, int v_min=0, int v_max=0, const char *display_format="%.0f")
Definition: ImGui.cpp:9196
int DataSize
Definition: ImGui.h:1324
IMGUI_API bool InputFloat2(const char *label, float v[2], int decimal_precision=-1, ImGuiInputTextFlags extra_flags=0)
Definition: ImGui.cpp:10505
GLint GLint GLsizei GLint border
IMGUI_API void LabelTextV(const char *label, const char *fmt, va_list args) IM_FMTLIST(2)
Definition: ImGui.cpp:7433
static float GetColumnsRectHalfWidth()
Definition: ImGui.cpp:12344
static ImGuiColumnsSet * FindOrAddColumnsSet(ImGuiWindow *window, ImGuiID id)
Definition: ImGui.cpp:12455
IMGUI_API void Shutdown(ImGuiContext *context)
Definition: ImGui.cpp:3610
float z
Definition: ImGui.h:130
IMGUI_API bool InputFloat4(const char *label, float v[4], int decimal_precision=-1, ImGuiInputTextFlags extra_flags=0)
Definition: ImGui.cpp:10515
ImVec2 WindowPadding
Definition: _ImGui.h:920
GLdouble GLdouble GLdouble y2
static void STB_TEXTEDIT_DELETECHARS(STB_TEXTEDIT_STRING *obj, int pos, int n)
Definition: ImGui.cpp:9633
IMGUI_API ImFont * GetFont()
Definition: ImGui.cpp:7066
IMGUI_API void EndGroup()
Definition: ImGui.cpp:12205
IMGUI_API float GetTime()
Definition: ImGui.cpp:2655
bool Appearing
Definition: _ImGui.h:936
IMGUI_API bool IsWindowNavFocusable(ImGuiWindow *window)
Definition: ImGui.cpp:6779
IMGUI_API void ShadeVertsLinearColorGradientKeepAlpha(ImDrawVert *vert_start, ImDrawVert *vert_end, ImVec2 gradient_p0, ImVec2 gradient_p1, ImU32 col0, ImU32 col1)
Definition: Draw.cpp:1232
bool KeysDown[512]
Definition: ImGui.h:1021
IMGUI_API int GetColumnIndex()
Definition: ImGui.cpp:12322
bool empty() const
Definition: ImGui.h:1122
IMGUI_API void ChannelsMerge()
Definition: Draw.cpp:499
IMGUI_API bool IsKeyReleased(int user_key_index)
Definition: ImGui.cpp:4527
static int ImMin(int lhs, int rhs)
Definition: _ImGui.h:141
IMGUI_API void Spacing()
Definition: ImGui.cpp:12150
IMGUI_API void LogToFile(int max_depth=-1, const char *filename=NULL)
Definition: ImGui.cpp:7825
GLboolean GLboolean GLboolean GLboolean a
IMGUI_API void VerticalSeparator()
Definition: ImGui.cpp:12084
IMGUI_API bool InputFloat(const char *label, float *v, float step=0.0f, float step_fast=0.0f, int decimal_precision=-1, ImGuiInputTextFlags extra_flags=0)
Definition: ImGui.cpp:10461
IMGUI_API ImGuiContext * GetCurrentContext()
Definition: ImGui.cpp:2596
static void SetWindowScrollY(ImGuiWindow *window, float new_scroll_y)
Definition: ImGui.cpp:6811
static void SetCursorPosYAndSetupDummyPrevLine(float pos_y, float line_height)
Definition: ImGui.cpp:1809
static int STB_TEXTEDIT_MOVEWORDRIGHT_IMPL(STB_TEXTEDIT_STRING *obj, int idx)
Definition: ImGui.cpp:9628
void reserve(int new_capacity)
Definition: ImGui.h:1144
IMGUI_API void SetWindowFocus()
Definition: ImGui.cpp:6927
IMGUI_API void EndCombo()
Definition: ImGui.cpp:10665
#define IM_COL32_G_SHIFT
Definition: ImGui.h:1350
float ScrollbarRounding
Definition: ImGui.h:937
int NavLayerActiveMaskNext
Definition: _ImGui.h:851
char DataType[12+1]
Definition: ImGui.h:1330
IMGUI_API bool IsWindowCollapsed()
Definition: ImGui.cpp:6909
IMGUI_API void SetCursorPosX(float x)
Definition: ImGui.cpp:7116
unsigned long int size_t
Definition: LibC/STDDef.h:57
static void LoadIniSettingsFromMemory(const char *buf)
Definition: ImGui.cpp:3706
IMGUI_API void Initialize(ImGuiContext *context)
Definition: ImGui.cpp:3591
static void SetWindowPos(ImGuiWindow *window, const ImVec2 &pos, ImGuiCond cond)
Definition: ImGui.cpp:6818
IMGUI_API float GetContentRegionAvailWidth()
Definition: ImGui.cpp:7012
ImVec2 CursorPos
Definition: _ImGui.h:831
bool KeyShift
Definition: ImGui.h:1018
static int STB_TEXTEDIT_KEYTOTEXT(int key)
Definition: ImGui.cpp:9606
float PopupBorderSize
Definition: ImGui.h:927
ImVector< ImGuiWindowSettings > SettingsWindows
Definition: _ImGui.h:696
IMGUI_API void AddImage(ImTextureID user_texture_id, const ImVec2 &a, const ImVec2 &b, const ImVec2 &uv_a=ImVec2(0, 0), const ImVec2 &uv_b=ImVec2(1, 1), ImU32 col=0xFFFFFFFF)
Definition: Draw.cpp:1133
IMGUI_API void PushItemWidth(float item_width)
Definition: ImGui.cpp:6401
bool ImTriangleContainsPoint(const ImVec2 &a, const ImVec2 &b, const ImVec2 &c, const ImVec2 &p)
Definition: ImGui.cpp:941
IMGUI_API ImGuiContext * CreateContext(ImFontAtlas *shared_font_atlas=NULL)
Definition: ImGui.cpp:2617
IMGUI_API bool Button(const char *label, const ImVec2 &size=ImVec2(0, 0))
Definition: ImGui.cpp:7650
ImVec2 ScrollTargetCenterRatio
Definition: _ImGui.h:927
IMGUI_API void Value(const char *prefix, bool b)
Definition: ImGui.cpp:12680
IMGUI_API bool IsItemFocused()
Definition: ImGui.cpp:4669
static void SettingsHandlerWindow_ReadLine(ImGuiContext *, ImGuiSettingsHandler *, void *entry, const char *line)
Definition: ImGui.cpp:3545
int FocusIdxTabRequestCurrent
Definition: _ImGui.h:980
IMGUI_API void Separator()
Definition: ImGui.cpp:12037
IMGUI_API void End()
Definition: ImGui.cpp:6195
ImGuiID ChildId
Definition: _ImGui.h:924
int ImStrlenW(const ImWchar *str)
Definition: ImGui.cpp:1012
void clear()
Definition: ImGui.h:1129
#define IM_COL32_A_SHIFT
Definition: ImGui.h:1352
IMGUI_API void FocusableItemUnregister(ImGuiWindow *window)
Definition: ImGui.cpp:2531
static ImGuiWindowSettings * AddWindowSettings(const char *name)
Definition: ImGui.cpp:3674
static bool InputTextFilterCharacter(unsigned int *p_char, ImGuiInputTextFlags flags, ImGuiTextEditCallback callback, void *user_data)
Definition: ImGui.cpp:9740
IMGUI_API void ItemSize(const ImVec2 &size, float text_offset_y=0.0f)
Definition: ImGui.cpp:2114
Definition: ImGui.h:128
IMGUI_API void BeginGroup()
Definition: ImGui.cpp:12182
bool FontAllowUserScaling
Definition: ImGui.h:977
GLboolean GLboolean GLboolean b
IMGUI_API bool DragFloatRange2(const char *label, float *v_current_min, float *v_current_max, float v_speed=1.0f, float v_min=0.0f, float v_max=0.0f, const char *display_format="%.3f", const char *display_format_max=NULL, float power=1.0f)
Definition: ImGui.cpp:9123
ImVec4 BackupValue
Definition: _ImGui.h:355
IMGUI_API bool SliderFloat4(const char *label, float v[4], float v_min, float v_max, const char *display_format="%.3f", float power=1.0f)
Definition: ImGui.cpp:8885
int ImGuiTreeNodeFlags
Definition: ImGui.h:103
IMGUI_API void AddCircleFilled(const ImVec2 &centre, float radius, ImU32 col, int num_segments=12)
Definition: Draw.cpp:1079
void * memset(void *s, const int c, size_t n)
Definition: Memory.c:63
#define STB_TEXTEDIT_STRING
Definition: _ImGui.h:64
IMGUI_API float GetScrollX()
Definition: ImGui.cpp:7149
IMGUI_API void Begin(int items_count, float items_height=-1.0f)
Definition: ImGui.cpp:1824
ImTextureID TexID
Definition: ImGui.h:1719
ImVec2 CursorMaxPos
Definition: _ImGui.h:834
#define NAV_MAP_KEY(_KEY, _NAV_INPUT)
float StartPosY
Definition: _ImGui.h:475
bool MouseDown[5]
Definition: ImGui.h:1013
IMGUI_API bool SliderInt4(const char *label, int v[4], int v_min, int v_max, const char *display_format="%.0f")
Definition: ImGui.cpp:8927
bool HasSelection() const
Definition: _ImGui.h:414
float GroupOffsetX
Definition: _ImGui.h:870
bool WasActive
Definition: _ImGui.h:931
bool ScrollbarY
Definition: _ImGui.h:928
IMGUI_API bool Combo(const char *label, int *current_item, const char *const items[], int items_count, int popup_max_height_in_items=-1)
Definition: ImGui.cpp:10745
unsigned short ImDrawIdx
Definition: ImGui.h:1436
IMGUI_API bool DragFloat(const char *label, float *v, float v_speed=1.0f, float v_min=0.0f, float v_max=0.0f, const char *display_format="%.3f", float power=1.0f)
Definition: ImGui.cpp:9020
IMGUI_API bool BeginPopupContextVoid(const char *str_id=NULL, int mouse_button=1)
Definition: ImGui.cpp:5040
static int is_word_boundary_from_right(STB_TEXTEDIT_STRING *obj, int idx)
Definition: ImGui.cpp:9622
unsigned int _VtxCurrentIdx
Definition: ImGui.h:1499
void FixInverted()
Definition: _ImGui.h:347
#define IM_COL32_R_SHIFT
Definition: ImGui.h:1349
IMGUI_API float GetColumnWidth(int column_index=-1)
Definition: ImGui.cpp:12401
IMGUI_API ImVec2 GetWindowSize()
Definition: ImGui.cpp:6846
IMGUI_API void RenderColorRectWithAlphaCheckerboard(ImVec2 p_min, ImVec2 p_max, ImU32 fill_col, float grid_step, ImVec2 grid_off, float rounding=0.0f, int rounding_corners_flags=~0)
Definition: ImGui.cpp:11294
int ImGuiWindowFlags
Definition: ImGui.h:104
char * ImStrchrRange(const char *str, const char *str_end, char c)
Definition: ImGui.cpp:1004
float PrevLineTextBaseOffset
Definition: _ImGui.h:838
ImVec2 ContentSizeVal
Definition: _ImGui.h:548
IMGUI_API void EndPopup()
Definition: ImGui.cpp:4991
float MenuBarOffsetX
Definition: _ImGui.h:853
IMGUI_API float GetTreeNodeToLabelSpacing()
Definition: ImGui.cpp:8235
bool KeyCtrl
Definition: ImGui.h:1017
IMGUI_API ImVec2 GetFontTexUvWhitePixel()
Definition: ImGui.cpp:7076
#define IM_NEWLINE
Definition: _ImGui.h:87
ImGuiWindow * ParentWindow
Definition: _ImGui.h:449
static float OffsetNormToPixels(const ImGuiColumnsSet *columns, float offset_norm)
Definition: ImGui.cpp:12334
IMGUI_API void RenderTextWrapped(ImVec2 pos, const char *text, const char *text_end, float wrap_width)
Definition: ImGui.cpp:4195
#define STB_TEXTEDIT_K_LINESTART
Definition: ImGui.cpp:9676
static ImVec2 CalcNextScrollFromScrollTargetAndClamp(ImGuiWindow *window)
Definition: ImGui.cpp:5382
IMGUI_API void ClearDragDrop()
Definition: ImGui.cpp:12713
IMGUI_API void TextV(const char *fmt, va_list args) IM_FMTLIST(1)
Definition: ImGui.cpp:7250
IMGUI_API void RenderBullet(ImVec2 pos)
Definition: ImGui.cpp:4317
IMGUI_API void NextColumn()
Definition: ImGui.cpp:12288
IMGUI_API bool ColorButton(const char *desc_id, const ImVec4 &col, ImGuiColorEditFlags flags=0, ImVec2 size=ImVec2(0, 0))
Definition: ImGui.cpp:11346
float x
Definition: ImGui.h:130
ImVector< ImGuiPopupRef > OpenPopupStack
Definition: _ImGui.h:615
int ImGuiMouseCursor
Definition: ImGui.h:89
bool AdvanceCursor
Definition: _ImGui.h:379
float IndentSpacing
Definition: ImGui.h:934
ImGuiItemStatusFlags LastItemStatusFlags
Definition: _ImGui.h:843
IMGUI_API float GetWindowHeight()
Definition: ImGui.cpp:6791
#define IM_COL32_B_SHIFT
Definition: ImGui.h:1351
IMGUI_API bool ButtonEx(const char *label, const ImVec2 &size_arg=ImVec2(0, 0), ImGuiButtonFlags flags=0)
Definition: ImGui.cpp:7611
ImVector< char > PrivateClipboard
Definition: _ImGui.h:690
IMGUI_API bool DragFloat2(const char *label, float v[2], float v_speed=1.0f, float v_min=0.0f, float v_max=0.0f, const char *display_format="%.3f", float power=1.0f)
Definition: ImGui.cpp:9108
int HiddenFrames
Definition: _ImGui.h:946
const void * Data
Definition: ImGui.h:1323
ImGuiPlotArrayGetterData(const float *values, int stride)
Definition: ImGui.cpp:9341
IMGUI_API bool BeginMainMenuBar()
Definition: ImGui.cpp:11012
IMGUI_API ImU32 ColorConvertFloat4ToU32(const ImVec4 &in)
Definition: ImGui.cpp:1320
ImVec2 DisplaySafeAreaPadding
Definition: ImGui.h:942
ImGuiCond SetWindowCollapsedAllowFlags
Definition: _ImGui.h:949
IMGUI_API bool SliderFloatN(const char *label, float *v, int components, float v_min, float v_max, const char *display_format, float power)
Definition: ImGui.cpp:8848
ImVec2 OpenMousePos
Definition: _ImGui.h:453
static void(* GImAllocatorFreeFunc)(void *ptr, void *user_data)
Definition: ImGui.cpp:775
float BackupGroupOffsetX
Definition: _ImGui.h:374
IMGUI_API void BeginColumns(const char *str_id, int count, ImGuiColumnsFlags flags=0)
Definition: ImGui.cpp:12467
IMGUI_API void AddRectFilled(const ImVec2 &a, const ImVec2 &b, ImU32 col, float rounding=0.0f, int rounding_corners_flags=ImDrawCornerFlags_All)
Definition: Draw.cpp:992
IMGUI_API void PushFont(ImFont *font)
Definition: ImGui.cpp:6464
ImRect NavRectRel[2]
Definition: _ImGui.h:973
float SettingsDirtyTimer
Definition: _ImGui.h:695
ImGuiWindow * CurrentWindow
Definition: _ImGui.h:594
IMGUI_API void SetNextWindowPos(const ImVec2 &pos, ImGuiCond cond=0, const ImVec2 &pivot=ImVec2(0, 0))
Definition: ImGui.cpp:6945
ImVec2 DisplayWindowPadding
Definition: ImGui.h:941
IMGUI_API void SetClipboardText(const char *text)
Definition: ImGui.cpp:2583
ImVec2 GetTR() const
Definition: _ImGui.h:333
float IniSavingRate
Definition: ImGui.h:964
IMGUI_API bool InvisibleButton(const char *str_id, const ImVec2 &size)
Definition: ImGui.cpp:7668
float y
Definition: ImGui.h:119
const char * TypeName
Definition: _ImGui.h:434
IMGUI_API void SetBool(ImGuiID key, bool val)
Definition: ImGui.cpp:1587
ImGuiStyle Style
Definition: _ImGui.h:579
int ImGuiCol
Definition: ImGui.h:85
static void AddWindowToDrawDataSelectLayer(ImGuiWindow *window)
Definition: ImGui.cpp:3879
void ClearSelection()
Definition: _ImGui.h:415
IMGUI_API void appendfv(const char *fmt, va_list args) IM_FMTLIST(2)
Definition: ImGui.cpp:1731
#define IM_F32_TO_INT8_SAT(_VAL)
Definition: ImGui.cpp:926
IMGUI_API void EndChild()
Definition: ImGui.cpp:5107
void Update(int count, float spacing, bool clear)
Definition: ImGui.cpp:1772
IMGUI_API float GetWindowContentRegionWidth()
Definition: ImGui.cpp:7030
IMGUI_API float GetScrollMaxX()
Definition: ImGui.cpp:7159
ImDrawListFlags Flags
Definition: ImGui.h:1496
ImVec2 FramePadding
Definition: ImGui.h:928
static ImGuiWindow * CreateNewWindow(const char *name, ImVec2 size, ImGuiWindowFlags flags)
Definition: ImGui.cpp:5261
static int STB_TEXTEDIT_MOVEWORDLEFT_IMPL(STB_TEXTEDIT_STRING *obj, int idx)
Definition: ImGui.cpp:9623
IMGUI_API bool BeginMenu(const char *label, bool enabled=true)
Definition: ImGui.cpp:11111
#define STB_TEXTEDIT_K_UNDO
Definition: ImGui.cpp:9682
IMGUI_API float GetTextLineHeightWithSpacing()
Definition: ImGui.cpp:7042
IMGUI_API void TextWrapped(const char *fmt,...) IM_FMTARGS(1)
Definition: ImGui.cpp:7307
IMGUI_API void ListBoxFooter()
Definition: ImGui.cpp:10907
IMGUI_API void TextColored(const ImVec4 &col, const char *fmt,...) IM_FMTARGS(2)
Definition: ImGui.cpp:7276
ImGuiAxis
Definition: _ImGui.h:243
ImVec4 Colors[ImGuiCol_COUNT]
Definition: ImGui.h:947
#define STB_TEXTEDIT_K_TEXTEND
Definition: ImGui.cpp:9679
IMGUI_API void RenderFrame(ImVec2 p_min, ImVec2 p_max, ImU32 fill_col, bool border=true, float rounding=0.0f)
Definition: ImGui.cpp:4254
ImGuiWindowFlags Flags
Definition: _ImGui.h:911
void PrimVtx(const ImVec2 &pos, const ImVec2 &uv, ImU32 col)
Definition: ImGui.h:1572
IMGUI_API float CalcItemWidth()
Definition: ImGui.cpp:6429
IMGUI_API void SetInt(ImGuiID key, int val)
Definition: ImGui.cpp:1576
static ImVec2 FindBestWindowPosForPopup(const ImVec2 &ref_pos, const ImVec2 &size, ImGuiDir *last_dir, const ImRect &r_avoid, ImGuiPopupPositionPolicy policy=ImGuiPopupPositionPolicy_Default)
Definition: ImGui.cpp:5187
ImDrawCallback UserCallback
Definition: ImGui.h:1428
int TotalIdxCount
Definition: ImGui.h:1584
IMGUI_API int GetKeyPressedAmount(int key_index, float repeat_delay, float rate)
Definition: ImGui.cpp:4505
IMGUI_API void Text(const char *fmt,...) IM_FMTARGS(1)
Definition: ImGui.cpp:7261
static void STB_TEXTEDIT_LAYOUTROW(StbTexteditRow *r, STB_TEXTEDIT_STRING *obj, int line_start_idx)
Definition: ImGui.cpp:9608
IMGUI_API void LogToTTY(int max_depth=-1)
Definition: ImGui.cpp:7809
float MouseDoubleClickMaxDist
Definition: ImGui.h:968
float GrabRounding
Definition: ImGui.h:939
ImDrawVert * _VtxWritePtr
Definition: ImGui.h:1500
ImGuiLayoutType ParentLayoutType
Definition: _ImGui.h:857
float FontGlobalScale
Definition: ImGui.h:976
static float GetScrollMaxY(ImGuiWindow *window)
Definition: ImGui.cpp:5377
IMGUI_API ImVec2 GetCursorScreenPos()
Definition: ImGui.cpp:7136
IMGUI_API ImGuiWindow * FindWindowByName(const char *name)
Definition: ImGui.cpp:5254
static bool ImIsPowerOfTwo(int v)
Definition: _ImGui.h:102
GLuint GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat t0
IMGUI_API void NavMoveRequestCancel()
Definition: ImGui.cpp:2329
IMGUI_API bool DragIntN(const char *label, int *v, int components, float v_speed, int v_min, int v_max, const char *display_format)
Definition: ImGui.cpp:9159
#define NULL
Definition: LibC/STDDef.h:41
float MaxX
Definition: _ImGui.h:474
int ImTextStrToUtf8(char *buf, int buf_size, const ImWchar *in_text, const ImWchar *in_text_end)
Definition: ImGui.cpp:1280
bool KeySuper
Definition: ImGui.h:1020
void(* RenderDrawListsFn)(ImDrawData *data)
Definition: ImGui.h:1005
char * ImStrdup(const char *str)
Definition: ImGui.cpp:997
IMGUI_API void EndChildFrame()
Definition: ImGui.cpp:5159
int FocusIdxAllCounter
Definition: _ImGui.h:977
IMGUI_API bool SliderInt3(const char *label, int v[3], int v_min, int v_max, const char *display_format="%.0f")
Definition: ImGui.cpp:8922
IMGUI_API bool BeginDragDropSource(ImGuiDragDropFlags flags=0)
Definition: ImGui.cpp:12725
IMGUI_API ImGuiStyle()
Definition: ImGui.cpp:783
IMGUI_API void OpenPopupEx(ImGuiID id)
Definition: ImGui.cpp:4788
static ImVec2 ImRotate(const ImVec2 &v, float cos_a, float sin_a)
Definition: _ImGui.h:164
IMGUI_API bool SliderInt(const char *label, int *v, int v_min, int v_max, const char *display_format="%.0f")
Definition: ImGui.cpp:8827
void push_back(const value_type &v)
Definition: ImGui.h:1157
static void CalcResizePosSizeFromAnyCorner(ImGuiWindow *window, const ImVec2 &corner_target, const ImVec2 &corner_norm, ImVec2 *out_pos, ImVec2 *out_size)
Definition: ImGui.cpp:5409
static size_t GImAllocatorActiveAllocationsCount
Definition: ImGui.cpp:777
IMGUI_API void PopItemWidth()
Definition: ImGui.cpp:6422
ImGuiID ID
Definition: _ImGui.h:468
float BackupLogLinePosY
Definition: _ImGui.h:377
IMGUI_API void SetNextWindowBgAlpha(float alpha)
Definition: ImGui.cpp:6989
float KeyRepeatDelay
Definition: ImGui.h:971
IMGUI_API void BringWindowToBack(ImGuiWindow *window)
Definition: ImGui.cpp:6341
static bool BeginChildEx(const char *name, ImGuiID id, const ImVec2 &size_arg, bool border, ImGuiWindowFlags extra_flags)
Definition: ImGui.cpp:5050
IMGUI_API void TreePop()
Definition: ImGui.cpp:12662
float MouseDragThreshold
Definition: ImGui.h:969
int TotalVtxCount
Definition: ImGui.h:1583
IMGUI_API void ScaleAllSizes(float scale_factor)
Definition: ImGui.cpp:820
IMGUI_API bool DragFloatN(const char *label, float *v, int components, float v_speed, float v_min, float v_max, const char *display_format, float power)
Definition: ImGui.cpp:9081
ImVec2 ImTriangleClosestPoint(const ImVec2 &a, const ImVec2 &b, const ImVec2 &c, const ImVec2 &p)
Definition: ImGui.cpp:960
value_type * iterator
Definition: ImGui.h:1116
IMGUI_API void PathArcTo(const ImVec2 &centre, float radius, float a_min, float a_max, int num_segments=10)
Definition: Draw.cpp:881
int NavLayerCurrent
Definition: _ImGui.h:848
IMGUI_API ImDrawList * GetOverlayDrawList()
Definition: ImGui.cpp:2665
float IndentX
Definition: _ImGui.h:869
ImVec2 MousePosPrev
Definition: ImGui.h:1050
IMGUI_API void BeginTooltipEx(ImGuiWindowFlags extra_flags, bool override_previous_tooltip=true)
Definition: ImGui.cpp:4741
Definition: _ImGui.h:1020
ImVec2 TexUvWhitePixel
Definition: ImGui.h:1730
IMGUI_API void EndColumns()
Definition: ImGui.cpp:12541
int FocusIdxAllRequestNext
Definition: _ImGui.h:981
bool AntiAliasedLines
Definition: ImGui.h:944
IMGUI_API bool InputScalarEx(const char *label, ImGuiDataType data_type, void *data_ptr, void *step_ptr, void *step_fast_ptr, const char *scalar_format, ImGuiInputTextFlags extra_flags)
Definition: ImGui.cpp:10405
ImVec2 ScrollbarSizes
Definition: _ImGui.h:929
IMGUI_API void LogText(const char *fmt,...) IM_FMTARGS(1)
Definition: ImGui.cpp:4095
IMGUI_API bool IsItemVisible()
Definition: ImGui.cpp:4698
IMGUI_API int * GetIntRef(ImGuiID key, int default_val=0)
Definition: ImGui.cpp:1546
IMGUI_API bool ButtonBehavior(const ImRect &bb, ImGuiID id, bool *out_hovered, bool *out_held, ImGuiButtonFlags flags=0)
Definition: ImGui.cpp:7466
static bool Items_SingleStringGetter(void *data, int idx, const char **out_text)
Definition: ImGui.cpp:10724
int AutoFitChildAxises
Definition: _ImGui.h:944
IMGUI_API bool BeginDragDropTarget()
Definition: ImGui.cpp:12897
ImVector< float > TextWrapPosStack
Definition: _ImGui.h:865
Definition: ImGui.h:1739
ImWchar InputCharacters[16+1]
Definition: ImGui.h:1022
IMGUI_API void EndFrame()
Definition: ImGui.cpp:3936
IMGUI_API int CalcTypematicPressedRepeatAmount(float t, float t_prev, float repeat_delay, float repeat_rate)
Definition: ImGui.cpp:4495
IMGUI_API float GetTextLineHeight()
Definition: ImGui.cpp:7036
IMGUI_API bool ItemHoverable(const ImRect &bb, ImGuiID id)
Definition: ImGui.cpp:2473
IMGUI_API bool SliderInt2(const char *label, int v[2], int v_min, int v_max, const char *display_format="%.0f")
Definition: ImGui.cpp:8917
IMGUI_API void PushStyleColor(ImGuiCol idx, ImU32 col)
Definition: ImGui.cpp:6534
IMGUI_API void LabelText(const char *label, const char *fmt,...) IM_FMTARGS(2)
Definition: ImGui.cpp:7458
IMGUI_API void PlotEx(ImGuiPlotType plot_type, const char *label, float(*values_getter)(void *data, int idx), void *data, int values_count, int values_offset, const char *overlay_text, float scale_min, float scale_max, ImVec2 graph_size)
Definition: ImGui.cpp:9226
IMGUI_API ImGuiID GetActiveID()
Definition: ImGui.cpp:2039
bool Delivery
Definition: ImGui.h:1332
static ImU32 ImAlphaBlendColor(ImU32 col_a, ImU32 col_b)
Definition: ImGui.cpp:11283
ImGuiCond FocusCond
Definition: _ImGui.h:543
ImGuiConfigFlags ConfigFlags
Definition: ImGui.h:963
IMGUI_API void SetActiveID(ImGuiID id, ImGuiWindow *window)
Definition: ImGui.cpp:2022
IMGUI_API bool MenuItem(const char *label, const char *shortcut=NULL, bool selected=false, bool enabled=true)
Definition: ImGui.cpp:10959
ImGuiWindow * NavWindow
Definition: _ImGui.h:622
static ImGuiWindow * FindHoveredWindow()
Definition: ImGui.cpp:4438
ImVec2 GetBR() const
Definition: _ImGui.h:335
IMGUI_API bool CloseButton(ImGuiID id, const ImVec2 &pos, float radius)
Definition: ImGui.cpp:7688
int AutoFitFramesY
Definition: _ImGui.h:942
#define STB_TEXTEDIT_K_DOWN
Definition: ImGui.cpp:9675
void PathLineTo(const ImVec2 &pos)
Definition: ImGui.h:1542
static void NavUpdate()
Definition: ImGui.cpp:2951
ImGuiID ID
Definition: _ImGui.h:910
void *(* ReadOpenFn)(ImGuiContext *ctx, ImGuiSettingsHandler *handler, const char *name)
Definition: _ImGui.h:436
IMGUI_API int GetFrameCount()
Definition: ImGui.cpp:2660
float FrameBorderSize
Definition: ImGui.h:930
IMGUI_API void End()
Definition: ImGui.cpp:1840
int ImGuiButtonFlags
Definition: _ImGui.h:47
bool HoveredIdAllowOverlap
Definition: _ImGui.h:598
static void DataTypeFormatString(ImGuiDataType data_type, void *data_ptr, const char *display_format, char *buf, int buf_size)
Definition: ImGui.cpp:8351
void * ImeWindowHandle
Definition: ImGui.h:1000
float BackupFloat[2]
Definition: _ImGui.h:362
int WantCaptureKeyboardNextFrame
Definition: _ImGui.h:711
IMGUI_API const char * GetClipboardText()
Definition: ImGui.cpp:2578
IMGUI_API bool Selectable(const char *label, bool selected=false, ImGuiSelectableFlags flags=0, const ImVec2 &size=ImVec2(0, 0))
Definition: ImGui.cpp:10767
ImGuiID PopupId
Definition: _ImGui.h:941
IMGUI_API void SetNextWindowContentSize(const ImVec2 &size)
Definition: ImGui.cpp:6969
IMGUI_API ImGuiIO()
Definition: ImGui.cpp:843
static const char * ImAtoi(const char *src, int *output)
Definition: ImGui.cpp:1048
bool NavMoveRequest
Definition: _ImGui.h:650
IMGUI_API void NavInitWindow(ImGuiWindow *window, bool force_reinit)
Definition: ImGui.cpp:2676
Definition: ImGui.h:955
static ImVec2 CalcSizeAutoFit(ImGuiWindow *window, const ImVec2 &size_contents)
Definition: ImGui.cpp:5348
IMGUI_API int GetKeyIndex(ImGuiKey imgui_key)
Definition: ImGui.cpp:4481
IMGUI_API void PopButtonRepeat()
Definition: ImGui.cpp:6514
ImVec2 CursorStartPos
Definition: _ImGui.h:833
IMGUI_API bool Checkbox(const char *label, bool *v)
Definition: ImGui.cpp:9409
int ImGuiSelectableFlags
Definition: ImGui.h:102
static bool IsNavInputPressed(ImGuiNavInput n, ImGuiInputReadMode mode)
Definition: ImGui.cpp:2758
float ItemWidth
Definition: _ImGui.h:861
float Time
Definition: _ImGui.h:585
ImVector< ImDrawVert > VtxBuffer
Definition: ImGui.h:1493
bool ActiveIdIsAlive
Definition: _ImGui.h:604
float Ascent
Definition: ImGui.h:1756
IMGUI_API bool TreeNodeBehaviorIsOpen(ImGuiID id, ImGuiTreeNodeFlags flags=0)
Definition: ImGui.cpp:7916
static ImVec2 InputTextCalcTextSizeW(const ImWchar *text_begin, const ImWchar *text_end, const ImWchar **remaining=NULL, ImVec2 *out_offset=NULL, bool stop_on_new_line=false)
Definition: ImGui.cpp:9555
IMGUI_API void SetNextWindowCollapsed(bool collapsed, ImGuiCond cond=0)
Definition: ImGui.cpp:6976
ImVec2 WindowTitleAlign
Definition: ImGui.h:923
static void ColorPickerOptionsPopup(ImGuiColorEditFlags flags, const float *ref_col)
Definition: ImGui.cpp:11471
static void NavUpdateWindowingHighlightWindow(int focus_change_dir)
Definition: ImGui.cpp:2784
IMGUI_API bool VSliderInt(const char *label, const ImVec2 &size, int *v, int v_min, int v_max, const char *display_format="%.0f")
Definition: ImGui.cpp:8837
IMGUI_API float CalcWrapWidthForPos(const ImVec2 &pos, float wrap_pos_x)
Definition: ImGui.cpp:2550
ImGuiIO IO
Definition: _ImGui.h:578
static void SaveIniSettingsToDisk(const char *ini_filename)
Definition: ImGui.cpp:3758
ImVec2 MouseDelta
Definition: ImGui.h:1044
IMGUI_API ImVec2 GetItemRectMax()
Definition: ImGui.cpp:4720
unsigned int ElemCount
Definition: ImGui.h:1425
ImVector< ImGuiColumnsSet > ColumnsStorage
Definition: _ImGui.h:962
IMGUI_API float GetScrollY()
Definition: ImGui.cpp:7154
static float SliderBehaviorCalcRatioFromValue(float v, float v_min, float v_max, float power, float linear_zero_pos)
Definition: ImGui.cpp:8533
IMGUI_API void SetCursorScreenPos(const ImVec2 &pos)
Definition: ImGui.cpp:7142
static int IMGUI_CDECL ChildWindowComparer(const void *lhs, const void *rhs)
Definition: ImGui.cpp:3807
#define IM_COL32(R, G, B, A)
Definition: ImGui.h:1355
int ImGuiSliderFlags
Definition: _ImGui.h:53
int ImGuiFocusedFlags
Definition: ImGui.h:99
IMGUI_API bool InputFloatN(const char *label, float *v, int components, int decimal_precision, ImGuiInputTextFlags extra_flags)
Definition: ImGui.cpp:10478
int MetricsActiveWindows
Definition: ImGui.h:1043
void Restore() const
Definition: _ImGui.h:1012
ImVec2 DisplayFramebufferScale
Definition: ImGui.h:979
ImGuiContext * GImGui
Definition: ImGui.cpp:760
IMGUI_API void LogToClipboard(int max_depth=-1)
Definition: ImGui.cpp:7853
IMGUI_API void BringWindowToFront(ImGuiWindow *window)
Definition: ImGui.cpp:6326
float FallbackAdvanceX
Definition: ImGui.h:1749
static void NavProcessMoveRequestWrapAround(ImGuiWindow *window)
Definition: ImGui.cpp:4979
IMGUI_API void EndMenuBar()
Definition: ImGui.cpp:11071
ImVec2 ButtonTextAlign
Definition: ImGui.h:940
IMGUI_API const char * GetVersion()
Definition: ImGui.cpp:2589
IMGUI_API float GetFrameHeight()
Definition: ImGui.cpp:7048
ImGuiID SourceParentId
Definition: ImGui.h:1328
int AutoFitFramesX
Definition: _ImGui.h:942
static void SetupDrawData(ImVector< ImDrawList *> *draw_lists, ImDrawData *out_draw_data)
Definition: ImGui.cpp:3907
bool CloseButton
Definition: _ImGui.h:937
ImVector< ImGuiGroupData > GroupStack
Definition: _ImGui.h:866
IMGUI_API void PushID(const char *str_id)
Definition: ImGui.cpp:8250
IMGUI_API bool DragIntRange2(const char *label, int *v_current_min, int *v_current_max, float v_speed=1.0f, int v_min=0, int v_max=0, const char *display_format="%.0f", const char *display_format_max=NULL)
Definition: ImGui.cpp:9201
bool WantMoveMouse
Definition: ImGui.h:1037
void(* ImGuiSizeCallback)(ImGuiSizeCallbackData *data)
Definition: ImGui.h:106
IMGUI_API ImGuiID GetID(const char *str_id)
Definition: ImGui.cpp:8281
bool KeyAlt
Definition: ImGui.h:1019
ImGuiID NavId
Definition: _ImGui.h:623
IMGUI_API bool InputTextEx(const char *label, char *buf, int buf_size, const ImVec2 &size_arg, ImGuiInputTextFlags flags, ImGuiTextEditCallback callback=NULL, void *user_data=NULL)
Definition: ImGui.cpp:9796
IMGUI_API void PushAllowKeyboardFocus(bool allow_keyboard_focus)
Definition: ImGui.cpp:6499
static void SetClipboardTextFn_DefaultImpl(void *user_data, const char *text)
Definition: ImGui.cpp:13049
float TitleBarHeight() const
Definition: _ImGui.h:996
bool Overlaps(const ImRect &r) const
Definition: _ImGui.h:338
ImVector< ImGuiID > IDStack
Definition: _ImGui.h:954
ImGuiMouseCursor MouseCursor
Definition: _ImGui.h:661
ImVector< float > IndexAdvanceX
Definition: ImGui.h:1746
static void CheckStacksSize(ImGuiWindow *window, bool write)
Definition: ImGui.cpp:5167
int ImStricmp(const char *str1, const char *str2)
Definition: ImGui.cpp:976
ImGuiDir
Definition: _ImGui.h:263
bool SelectedAllMouseLock
Definition: _ImGui.h:409
float KeyRepeatRate
Definition: ImGui.h:972
static void SaveIniSettingsToMemory(ImVector< char > &out_buf)
Definition: ImGui.cpp:3775
float MinX
Definition: _ImGui.h:474
ImGuiNextWindowData NextWindowData
Definition: _ImGui.h:617
static bool ImCharIsSpace(int c)
Definition: _ImGui.h:101
static ImGuiCol GetWindowBgColorIdxFromFlags(ImGuiWindowFlags flags)
Definition: ImGui.cpp:5400
ImVec2 TouchExtraPadding
Definition: ImGui.h:933
IMGUI_API void RenderTextClipped(const ImVec2 &pos_min, const ImVec2 &pos_max, const char *text, const char *text_end, const ImVec2 *text_size_if_known, const ImVec2 &align=ImVec2(0, 0), const ImRect *clip_rect=NULL)
Definition: ImGui.cpp:4214
ImRect Rect() const
Definition: _ImGui.h:994
ImGuiWindow * GetCurrentWindow()
Definition: _ImGui.h:1027
static void SetWindowSize(ImGuiWindow *window, const ImVec2 &size, ImGuiCond cond)
Definition: ImGui.cpp:6852
IMGUI_API void SetAllInt(int val)
Definition: ImGui.cpp:1614
float DeclColumns(float w0, float w1, float w2)
Definition: ImGui.cpp:1789
int ImTextCountUtf8BytesFromStr(const ImWchar *in_text, const ImWchar *in_text_end)
Definition: ImGui.cpp:1296
IMGUI_API ImVec2 GetWindowPos()
Definition: ImGui.cpp:6797
void Floor()
Definition: _ImGui.h:346
#define STB_TEXTEDIT_K_SHIFT
Definition: ImGui.cpp:9686
IMGUI_API bool DragInt2(const char *label, int v[2], float v_speed=1.0f, int v_min=0, int v_max=0, const char *display_format="%.0f")
Definition: ImGui.cpp:9186
void(* ReadLineFn)(ImGuiContext *ctx, ImGuiSettingsHandler *handler, void *entry, const char *line)
Definition: _ImGui.h:437
IMGUI_API ImGuiStyle & GetStyle()
Definition: ImGui.cpp:2642
IMGUI_API void ColorConvertRGBtoHSV(float r, float g, float b, float &out_h, float &out_s, float &out_v)
Definition: ImGui.cpp:1364
static ImVec2 CalcSizeContents(ImGuiWindow *window)
Definition: ImGui.cpp:5340
static void RenderArrowsForVerticalBar(ImDrawList *draw_list, ImVec2 pos, ImVec2 half_sz, float bar_w)
Definition: ImGui.cpp:11733
GLenum GLuint GLint GLint layer
int ImTextStrFromUtf8(ImWchar *buf, int buf_size, const char *in_text, const char *in_text_end, const char **in_text_remaining)
Definition: ImGui.cpp:1199
#define FLT_MAX
Definition: LibC/Float.h:99
IMGUI_API void SetItemAllowOverlap()
Definition: ImGui.cpp:4705
ImU32 TreeDepthMayJumpToParentOnPop
Definition: _ImGui.h:841
static void NavRestoreLayer(int layer)
Definition: ImGui.cpp:2305
IMGUI_API void CloseCurrentPopup()
Definition: ImGui.cpp:4895
IMGUI_API void PushClipRectFullScreen()
Definition: Draw.cpp:441
ImVec2 CursorPosPrevLine
Definition: _ImGui.h:832
static void SetWindowCollapsed(ImGuiWindow *window, bool collapsed, ImGuiCond cond)
Definition: ImGui.cpp:6893
IMGUI_API void PopClipRect()
Definition: ImGui.cpp:3928
IMGUI_API bool TreeNodeExV(const char *str_id, ImGuiTreeNodeFlags flags, const char *fmt, va_list args) IM_FMTLIST(3)
Definition: ImGui.cpp:8152
const char * IniFilename
Definition: ImGui.h:965
float MouseDownDurationPrev[5]
Definition: ImGui.h:1058
IMGUI_API void OpenPopup(const char *str_id)
Definition: ImGui.cpp:4826
ImGuiCond SizeConstraintCond
Definition: _ImGui.h:542
IMGUI_API bool DragInt3(const char *label, int v[3], float v_speed=1.0f, int v_min=0, int v_max=0, const char *display_format="%.0f")
Definition: ImGui.cpp:9191
IMGUI_API ImVec2 CalcItemSize(ImVec2 size, float default_x, float default_y)
Definition: ImGui.cpp:2537
float WindowBorderSize
Definition: ImGui.h:921
static void * MallocWrapper(size_t size, void *user_data)
Definition: ImGui.cpp:767
IMGUI_API ImGuiSettingsHandler * FindSettingsHandler(const char *type_name)
Definition: ImGui.cpp:3695
ImU32 ImHash(const void *data, int data_size, ImU32 seed)
Definition: ImGui.cpp:1092
ImFont * Font
Definition: _ImGui.h:580
IMGUI_API bool DragFloat3(const char *label, float v[3], float v_speed=1.0f, float v_min=0.0f, float v_max=0.0f, const char *display_format="%.3f", float power=1.0f)
Definition: ImGui.cpp:9113
GLuint GLfloat GLfloat GLfloat x1
int ImDrawListFlags
Definition: ImGui.h:92
IMGUI_API bool SliderFloat(const char *label, float *v, float v_min, float v_max, const char *display_format="%.3f", float power=1.0f)
Definition: ImGui.cpp:8714
ImVector< char > InitialText
Definition: _ImGui.h:401
#define STB_TEXTEDIT_K_REDO
Definition: ImGui.cpp:9683
ImVector< TextRange > Filters
Definition: ImGui.h:1203
iterator end()
Definition: ImGui.h:1132
IMGUI_API void SetCursorPosY(float y)
Definition: ImGui.cpp:7123
ImGuiWindow * Window
Definition: _ImGui.h:448
ImVec2 BackupCursorMaxPos
Definition: _ImGui.h:372
Definition: _ImGui.h:318
ImVec2 SizeContents
Definition: _ImGui.h:917
float Scale
Definition: ImGui.h:1743
ImVector< ImDrawIdx > IdxBuffer
Definition: ImGui.h:1492
IMGUI_API void TextDisabled(const char *fmt,...) IM_FMTARGS(1)
Definition: ImGui.cpp:7291
float StartMaxPosX
Definition: _ImGui.h:476
bool NextTreeNodeOpenVal
Definition: _ImGui.h:618
IMGUI_API ImDrawData * GetDrawData()
Definition: ImGui.cpp:2649
IMGUI_API void ClearActiveID()
Definition: ImGui.cpp:2067
static float GetMinimumStepAtDecimalPrecision(int decimal_precision)
Definition: ImGui.cpp:8509
IMGUI_API const ImVec4 & GetStyleColorVec4(ImGuiCol idx)
Definition: ImGui.cpp:1346
static bool DataTypeApplyOpFromText(const char *buf, const char *initial_value_buf, ImGuiDataType data_type, void *data_ptr, const char *scalar_format)
Definition: ImGui.cpp:8396
IMGUI_API void Columns(int count=1, const char *id=NULL, bool border=true)
Definition: ImGui.cpp:12609
int LastFrameActive
Definition: _ImGui.h:958
static void SetNavID(ImGuiID id, int nav_layer)
Definition: ImGui.cpp:2003
ImGuiStorage * StateStorage
Definition: _ImGui.h:855
bool AntiAliasedFill
Definition: ImGui.h:945
IMGUI_API void SetWindowFontScale(float scale)
Definition: ImGui.cpp:7081
ImVec2 Min
Definition: _ImGui.h:320
#define STB_TEXTEDIT_K_LINEEND
Definition: ImGui.cpp:9677
GLfloat GLfloat GLfloat GLfloat h
#define IM_COL32_BLACK
Definition: ImGui.h:1357
int memcmp(const void *cs, const void *ct, size_t n)
Definition: Memory.c:52
ImGuiDataType
Definition: _ImGui.h:256
#define IM_PI
Definition: _ImGui.h:83
IMGUI_API float GetFrameHeightWithSpacing()
Definition: ImGui.cpp:7054
IMGUI_API void InsertChars(int pos, const char *text, const char *text_end=NULL)
Definition: ImGui.cpp:9721
IMGUI_API bool DragInt(const char *label, int *v, float v_speed=1.0f, int v_min=0, int v_max=0, const char *display_format="%.0f")
Definition: ImGui.cpp:9149
IMGUI_API bool IsMouseDoubleClicked(int button)
Definition: ImGui.cpp:4576
bool Contains(const ImVec2 &p) const
Definition: _ImGui.h:336
static void AddWindowToSortedBuffer(ImVector< ImGuiWindow *> *out_sorted_windows, ImGuiWindow *window)
Definition: ImGui.cpp:3818
static void ClosePopupToLevel(int remaining)
Definition: ImGui.cpp:4874
ImFontAtlas * Fonts
Definition: ImGui.h:975
ImFont * FontDefault
Definition: ImGui.h:978
bool IsBeingResized
Definition: _ImGui.h:471
IMGUI_API void StyleColorsClassic(ImGuiStyle *dst=NULL)
Definition: Draw.cpp:182
IMGUI_API bool IsAnyItemActive()
Definition: ImGui.cpp:4686
ImVec2 WindowPadding
Definition: ImGui.h:919
static ImGuiDir NavScoreItemGetQuadrant(float dx, float dy)
Definition: ImGui.cpp:2145
GLsizei const GLfloat * values
IMGUI_API void EndMenu()
Definition: ImGui.cpp:11242
GLenum GLenum GLenum GLenum GLenum scale
float BackupCurrentLineHeight
Definition: _ImGui.h:375
IMGUI_API void PrimReserve(int idx_count, int vtx_count)
Definition: Draw.cpp:546
static bool IsNavInputPressedAnyOfTwo(ImGuiNavInput n1, ImGuiNavInput n2, ImGuiInputReadMode mode)
Definition: ImGui.cpp:2763
IMGUI_API void ColorConvertHSVtoRGB(float h, float s, float v, float &out_r, float &out_g, float &out_b)
Definition: ImGui.cpp:1386
IMGUI_API void PopID()
Definition: ImGui.cpp:8275
float WindowRounding
Definition: ImGui.h:920
IMGUI_API bool SetDragDropPayload(const char *type, const void *data, size_t size, ImGuiCond cond=0)
Definition: ImGui.cpp:12832
static void LoadIniSettingsFromDisk(const char *ini_filename)
Definition: ImGui.cpp:3684
IMGUI_API void PlotLines(const char *label, const float *values, int values_count, int values_offset=0, const char *overlay_text=NULL, float scale_min=FLT_MAX, float scale_max=FLT_MAX, ImVec2 graph_size=ImVec2(0, 0), int stride=sizeof(float))
Definition: ImGui.cpp:9351
IMGUI_API ImDrawListSharedData * GetDrawListSharedData()
Definition: ImGui.cpp:2670
int FrameCount
Definition: _ImGui.h:586
IMGUI_API void ChannelsSplit(int channels_count)
Definition: Draw.cpp:466
IMGUI_API float GetCursorPosY()
Definition: ImGui.cpp:7103
IMGUI_API void SetColorEditOptions(ImGuiColorEditFlags flags)
Definition: ImGui.cpp:11328
IMGUI_API bool BeginPopupEx(ImGuiID id, ImGuiWindowFlags extra_flags)
Definition: ImGui.cpp:4906
int OpenFrameCount
Definition: _ImGui.h:450
void Add(const ImVec2 &p)
Definition: _ImGui.h:339
IMGUI_API void SetKeyboardFocusHere(int offset=0)
Definition: ImGui.cpp:7213
IMGUI_API bool IsClippedEx(const ImRect &bb, ImGuiID id, bool clip_even_when_logged)
Definition: ImGui.cpp:2495
float ScrollbarSize
Definition: ImGui.h:936
IMGUI_API void LogFinish()
Definition: ImGui.cpp:7868
ImRect LastItemDisplayRect
Definition: _ImGui.h:845
bool NavAnyRequest
Definition: _ImGui.h:644
bool OptMacOSXBehaviors
Definition: ImGui.h:984
IMGUI_API int ParseFormatPrecision(const char *fmt, int default_value)
Definition: ImGui.cpp:8487
float AdvanceX
Definition: ImGui.h:1619
#define IM_F32_TO_INT8_UNBOUND(_VAL)
Definition: ImGui.cpp:925
#define IMGUI_CDECL
Definition: ImGui.cpp:683
void ImStrncpy(char *dst, const char *src, size_t count)
Definition: ImGui.cpp:990
ImGuiStyleVar VarIdx
Definition: _ImGui.h:361
ImGuiWindow * GetCurrentWindowRead()
Definition: _ImGui.h:1026
ImGuiInputReadMode
Definition: _ImGui.h:284
IMGUI_API void SetScrollX(float scroll_x)
Definition: ImGui.cpp:7169
ImVector< ImGuiPopupRef > CurrentPopupStack
Definition: _ImGui.h:616
IMGUI_API void PopFont()
Definition: ImGui.cpp:6474
ImVec2 ScrollTarget
Definition: _ImGui.h:926
float y
Definition: ImGui.h:130
ImVector< float > ItemWidthStack
Definition: _ImGui.h:864
IMGUI_API void Render()
Definition: ImGui.cpp:4026
IMGUI_API void TreeAdvanceToLabelPos()
Definition: ImGui.cpp:8228
IMGUI_API bool GetBool(ImGuiID key, bool default_val=false) const
Definition: ImGui.cpp:1524
float x
Definition: ImGui.h:119
int ImGuiNavDirSourceFlags
Definition: _ImGui.h:51
IMGUI_API bool InputInt(const char *label, int *v, int step=1, int step_fast=100, ImGuiInputTextFlags extra_flags=0)
Definition: ImGui.cpp:10471
GLuint GLsizei const GLchar * label
ImGuiCond SetWindowSizeAllowFlags
Definition: _ImGui.h:948
IMGUI_API ImVec4 ColorConvertU32ToFloat4(ImU32 in)
Definition: ImGui.cpp:1310
float MenuBarHeight() const
Definition: _ImGui.h:998
IMGUI_API ImU32 GetColorU32(ImGuiCol idx, float alpha_mul=1.0f)
Definition: ImGui.cpp:1330
static void NavUpdateWindowing()
Definition: ImGui.cpp:2800
float PopupRounding
Definition: ImGui.h:926
IMGUI_API void PopStyleColor(int count=1)
Definition: ImGui.cpp:6554
ImVector< ImGuiWindow * > ChildWindows
Definition: _ImGui.h:854
char TempBuffer[1024 *3+1]
Definition: _ImGui.h:713
int BeginOrderWithinParent
Definition: _ImGui.h:938
ImVector< unsigned short > IndexLookup
Definition: ImGui.h:1747
ImGuiID NavNextActivateId
Definition: _ImGui.h:629
int ImGuiKey
Definition: ImGui.h:87
int ImTextCountCharsFromUtf8(const char *in_text, const char *in_text_end)
Definition: ImGui.cpp:1218
ImVector< ImVec4 > _ClipRectStack
Definition: ImGui.h:1502
IMGUI_API void EndMainMenuBar()
Definition: ImGui.cpp:11030
value_type & back()
Definition: ImGui.h:1136
IMGUI_API bool VSliderFloat(const char *label, const ImVec2 &size, float *v, float v_min, float v_max, const char *display_format="%.3f", float power=1.0f)
Definition: ImGui.cpp:8774
float CalcExtraSpace(float avail_w)
Definition: ImGui.cpp:1800
IMGUI_API void TextDisabledV(const char *fmt, va_list args) IM_FMTLIST(1)
Definition: ImGui.cpp:7284
IMGUI_API bool IsAnyMouseDown()
Definition: ImGui.cpp:4542
IMGUI_API void NewLine()
Definition: ImGui.cpp:12272
IMGUI_API void SetWindowSize(const ImVec2 &size, ImGuiCond cond=0)
Definition: ImGui.cpp:6882
ImGuiID PopupId
Definition: _ImGui.h:447